C和C++常見誤區以及問題整理


c和c++的關系

c是面向過程的語言,c++是在c的基礎上擴展的面向對象的編程語言。
c++具備c的所有功能,對c的庫完全兼容。
c++的標准在98年確定,在那之前已經有一些庫大量使用。
新標准中,推出了名稱空間的概念,既是為了方便人們使用新標准的同時,不用大量修改之前的代碼,對之前的代碼兼容,同時可以有效的避免名稱沖突。
舊標准中以.h結尾
新標准沒有.h
舊標准中可以直接包含c的庫文件,編譯器會附帶c的兼容庫實現
新標准中有一樣的c庫子模塊支持,命名方式變更為:原stdio.h,新cstdio,即前面+c,后面去掉.h

C++標准庫(C++ Standard Library),是類庫和函數的集合。 
C++編譯器廠商根據C++標准委員會官方的ISO規范並將其轉化為代碼。
C++編譯器廠商在實現C++標准庫過程中必須依賴其不同操作系統所提供的系統調用接口,因此每個平台都有其自己的C++標准庫實現。
C++標准庫的特點如下:
A、C++標准庫不是C++語言標准的一部分,由類庫和函數庫組成。
B、C++標准庫中定義的類和對象都位於std命名空間中。
C、C++標准庫的頭文件都不帶.h后綴。
D、C++標准庫涵蓋了C庫的功能
E、C++標准庫中包含一個涵蓋C庫功能的子庫,通常頭文件以c開頭,如#include <cmath>#include <cstring>等。

如何理解名稱空間

命名空間存在的目的是為了解決源代碼中的重名問題。比如你寫代碼的時候需要用到矩陣計算,於是你定義了一個類,叫做Matrix。然后你引入的第三方庫中,也有一個叫做Matrix的類,於是乎就重名了。為了解決這個問題,只需要把它們放在不同的命名空間里,比如你的叫做foo::Matrix, 第三方庫的叫做third_party::Matrix,這樣它們就有了不同的名字,編譯器就可以正確識別出你在代碼中用的Matrix是哪一個。

這個時候如果你同時使用了using namespace foo,using namespace third_party,就又會使這兩個不同的類具有相同的標識符。因此在良好的編程風格中,盡可能的避免使用using namespace,或者僅在翻譯單元(可以理解為是一個cpp文件)內、函數內、類內使用(using具體的對象、函數)。

第二個問題是是不是所有的程序名字都要在std中。恰恰相反,C++標准禁止用戶自己擴充std命名空間,所以用戶的代碼應該是處於非std空間中,例如默認命名空間:: 。但是,事實上每一個編譯器都支持用戶在std空間中定義自己的類、函數、對象,因此在std實現自定義類的哈希函數也是可以編譯通過的,盡管這是一個違背標准的行為。

在刷算法時,可以隨意一點,按照這種方式使用

using namespace std; // avoid as too indiscriminate(隨意)

嚴謹一點可以這樣,最大限度地避免沖突的產生

using std::cin;
using std::cout;
using std::endl;
int x;
cin >> x;
cout << x << endl;

或者這樣

int x;
std::cin >> x ;
std::cout << x << std::endl;

However,

using namespace std;

is considered a bad practice because you are practically importing the whole standard namespace, thus opening up a lot of possibilities for name clashes. It is better to import only the stuff you are actually using in your code, like

using std::string;

字符串類型

C語言不支持真正意義上的字符串,但可以使用字符數組和一組函數實現字符串操作。C語言不支持自定義類型,因此也不能定義字符串類型。

C++語言可以自定義類型,可以通過類完成字符串類型的定義,但C++語言也沒有原生的字符串類型。C++語言通過C++標准庫提供的string類型實現對字符串類型的支持。string類的特性如下:
A、string直接支持字符串連接
B、string直接支持字符串的大小比較
C、string直接支持子串查找和提取
D、string直接支持字符串的插入和替換

變量聲明與定義

extern int i; //聲明,不是定義
int i; //聲明,也是定義
定義只能出現在一處。也就是說,不管是 int a 還是 int a=0 都只能出現一次,而 extern int a 可以出現很多次。
當你要引用一個全局變量的時候,你就要聲明 extern int a 這時候 extern 不能省略,因為省略了,就變成 int a 這是一個定義,不是聲明。

前綴指定基數:

  • 0x 或 0X 表示十六進制,
  • 0 表示八進制,
  • 0b表示二進制
  • 不帶前綴則默認表示十進制

后綴是 U 和 L 的組合,U 表示無符號整數(unsigned),L 表示長整數(long)。后綴可以是大寫,也可以是小寫,U 和 L 的順序任意。

結構數據類型

結構數據類型允許構造由多個基礎數據類型組合而成的復雜結構,結構數據類型為面向對象的藍本。以下的結構數據類型通過指針實現了二叉樹結構

typedef struct Bintree {
    int data;
    struct bintree *lchild; // left child of the node
    struct bintree *rchild; // right child of the node
} bintree; // 自定義 bintree 類型

&&,||,&,|

&&:邏輯與,前后條件同時滿足表達式為真
||:邏輯或,前后條件只要有一個滿足表達式為真
&:按位與
|:按位或
&&和||是邏輯運算,&與|是位運算

*,&

*的作用
1.乘號(Multiply)
2.聲明指針(Pointer Statement)

//就是聲明變量a是5,把a的地址附到指針ptr上
int a =5; int* ptr=&a;

3.解引用 (Dereference)

*ptr 單獨拿出來就是找出 ptr指針指向的值,按照第二點的說法就是5

&的作用

&叫做取地址符號
一般指針只能接受一個內存地址而不能接受一個值

//錯誤表達,指針不能接受一個值
int a =5; int* ptr=a;

//正確表達,把a的地址給指針ptr
int a =5; int* ptr=&a;

案例:

數據結構偽代碼理解
比如定義鏈表時:
typedef struct Node{

}Node,*Linklist;

在創建函數時候這樣,
int creatlist(Linklist &L){}

用這個函數時候需要這樣寫
creatlist(L);

而定義順序表時
typedef struct{
}List;

創建函數時候
int creatlist(List *l){}

用函數的時候
creatlist(&l);

解答

不關引用和題主C語言不好的事,事情應該是這樣的:
並不是你的教材和你的老師講錯了,這樣的代碼是有意為之。但是程序又跑不起來,那問題出在哪呢。問題就在於大多數數據結構教材一開始就告訴了你,
本書的算法都是用類C語言偽碼實現的,並非是嚴格意義上的C語言。在創建函數時候這樣,

int creatlist(Linklist &L){}

用這個函數時候需要這樣寫creatlist(L);

為什么這么創建(定義)函數呢?因為編書人想告訴你的是函數的參數並非變量本身,而是存放變量的地址(有些答主學了C++,看到&就是引用,真的,你太敏感了)。
為什么要這么調用呢?因為函數的定義,函數調用需要傳一個地址進去,那么傳一個指針進去是理所當然的。再來看這段代碼。而定義順序表時
typedef struct{
}List;

創建函數時候
int creatlist(List *l){}

用函數的時候
creatlist(&l);

WTF?看起來跟上面的定義和調用格式都完全不一樣哎,又懵逼了...其實是這樣的:為什么這樣創建(定義)函數呢?和上其實同理,如果這樣寫,typedef struct{
}List;

int creatlist(List l){}就是在說你只是傳了一個結構體進去。所以作者加個*,是想告訴你這里傳進去的是個順序表。
為什么這么調用呢?還是因為定義,函數需要一個地址,那么我們就傳一個地址進去。綜上所述,這幾段代碼肯定是跑不起來的,因為根本不是C語言代碼,只是偽代碼而已,那作者是吃多了才這么寫么?不是。作者只是想簡化用來實現算法的語言,因為數據結構中選用的語言根本不是重點,重點是各種數據結構的思想。換句話說作者沒想讓你把程序跑起來,作者只是想讓你能更容易懂。說到這里我想你應該很明白了,程序跑不起來書和老師都沒有錯(也不是某些答主說的C++中的引用或者你的C語言學得不好),既然作者已經將語法簡化得不能再簡化了,何妨不將教材上的偽代碼充分理解,然后選取一門語言自己實現它呢?或許作者選用偽代碼來講述也有這一層原因(逼你自己動手)吧。

參考鏈接:請問 C 語言中 & 和 * 的用法? - 陳思定的回答 - 知乎

gcc,g++,gdb,cc

gcc and g++ are compiler-drivers of the GNU Compiler Collection (which was once upon a time just the GNU C Compiler).Even though they automatically determine which backends (cc1 cc1plus ...) to call depending on the file-type, unless overridden with -x language, they have some differences.The probably most important difference in their defaults is which libraries they link against automatically.According to GCC's online documentation link options and how g++ is invoked, g++ is equivalent to gcc -xc++ -lstdc++ -shared-libgcc (the 1st is a compiler option, the 2nd two are linker options). This can be checked by running both with the -v option (it displays the backend toolchain commands being run).

  • GCC: GNU Compiler Collection

    • Referrers to all the different languages that are supported by the GNU compiler.
  • gcc: GNU C      Compiler

  • g++: GNU C++ Compiler

The main differences:

  • gcc will compile: *.c , *.cpp files as C and C++ respectively.
  • g++ will compile: *.c , *.cpp files but they will all be treated as C++ files.
  • Also if you use g++ to link the object files it automatically links in the std C++ libraries (gcc does not do this).
  • gcc compiling C files has fewer predefined macros(預定義宏命令).
  • gcc compiling *.cpp and g++ compiling *.c/*.cpp files has a few extra macros.

reference link


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM