《你必須知道的495個C語言問題》知識筆記及補充

2022-02-03 09:54:03 字數 4276 閱讀 3349

它可以用作一種格式上的提示表明函式的定義可能在另乙個原始檔中,但在

extern int f(); 和 int f(); 之間並沒有實質的區別。

補充:extern可以置於變數或者函式前,以標示變數或者函式的定義在別的檔案中,提示編譯器遇到此變數和函式時在其他模組中尋找其定義。此外extern也可用來進行鏈結指定。也就是說extern有兩個作用:

第 一,當它與"c"一起連用時,如: extern "c" void fun(int a, int

b);則告訴編譯器在編譯fun這個函式名時按著c的規則去翻譯相應的函式名而不是c++的,c++的規則在翻譯這個函式名時會把fun這個名字變得面目

全非,可能是fun@abc_int_int#%$也可能是別的,這要看編譯器的"脾氣"了(不同的編譯器採用的方法不一樣),為什麼這麼做呢,因為

c++支援函式的過載;

第二,當extern不與"c"在一起修飾變數 或函式時,如在標頭檔案中: extern int

g_int; 它的作用就是宣告函式或全域性變數的作用範圍的關鍵字,其宣告的函式和變數可以在本模組活其他模組中使用,記住它是乙個宣告不是定義!也就是

說b模組(編譯單元)要是引用模組(編譯單元)a中定義的全域性變數或函式時,它只要包含a模組的標頭檔案即可,在編譯階段,模組b雖然找不到該函式或變數,

但它不會報錯,它會在連線時從模組a生成的目標**中找到此函式。

這個問題至少有以下3種答案:

(1)char *(*(*a[n])())();

(2)用typedef逐步完成宣告:

typedef char *pc;        /* 字元指標 */  

typedef pc fpc(); /* 返回字元指標的函式 */

typedef fpc *pfpc; /* 上面函式的指標 */

typedef pfpc fpfpc(); /* 返回函式指標的函式 */

typedef fpfpc *pfpfpc; /* 上面函式的指標 */

pfpfpc a[n]; /* 上面指標的陣列 */

(3)使用cdecl程式,它可以把英文翻譯成c或者把c翻譯成英文:

通過型別轉換,cdecl也可以用於解釋複雜的宣告,指出引數應該進入哪一對括號(如同在上述的複雜函式定義中)。

補充:cdecl程式非常有用,它可以在c語言的宣告和英語之間進行轉換。它可以解釋乙個現存的c語言宣告,cdecl 程式可以幫助你分析複雜的宣告。

c不是c++。結構標籤不能自動生成型別。

補充:也就是在c++中這樣是對的。在c中不想用struct只能借助於typedef。

陣列自動分配空間,但是不能重分配或改變大小。指標必須明確賦值以指向分配的空間(可能使用malloc),但是可以隨意重新賦值(即指向不同的物件),同時除了表示乙個記憶體塊的基址之外,還有許多其它的用途。

由於陣列和指標所謂的等價性,陣列和指標經常看起來可以互換,而事實上指向malloc分配的記憶體塊的指標通常被看作乙個真正的陣列(也可以用引用)。但是,要小心sizeof。

陣列蛻化為指標的規則不能遞迴應用。陣列的陣列(即二維陣列)蛻化為陣列的指標,而不是指標的指標。陣列指標常常令人困惑,需要小心對待:

如果你向函式傳遞二維陣列:

int array[nrows][ncolumns];

f(array);

那麼函式的宣告必須匹配:

void f(int a[ncolumns])

或者void f(int (*ap)[ncolumns])  /* ap是個陣列指標 */

在第乙個宣告中,編譯器進行了通常的從「陣列的陣列」到「陣列的指標」的隱式轉換;第二種形式中的指標定義顯而易見。

因為被調函式並不為陣列分配位址,所以它並不需要知道總的大小,所以行數nrows可以省略。但陣列的寬度依然重要,所以列維度ncolumns(對於三維或多維陣列,相關的維度)必須保留。

如果乙個函式已經定義為接受指標的指標,那麼幾乎可以肯定直接向它傳入二維陣列毫無意義。

char *str;  

gets(str);

printf("%s\n", str);

str沒有指向任何合法的位置,換言之,我們不知道指標str指向何處。因為區域性變數沒有初始化,通常包含垃圾資訊,所以甚至都不能保證str是乙個合法的指標。

改正方法:用區域性變數或用malloc()分配str緩衝區。

未初始化的指標p所指向的隨機位址恰好對你來說是可寫的,而且顯然也沒有用於什麼關鍵的資料。

char *p; 編譯器只分配了足夠容納指標本身的記憶體; 也就是說,這種情況下,你分配了sizeo(char*)個位元組的記憶體。但你還沒有分配任何讓指標指向的記憶體,因此此時p所指向的記憶體可能是垃圾資訊也可能是可寫的區域,沒有崩潰說明是後者。

char *itoa(int n)  

這樣在編譯的時候會出現這樣的警告資訊「warning c4172: returning address of local variable or temporary」,說明retbuf的位址是臨時變數,是暫時的,函式返回時就沒有了也就是不能直接返回。

一種解決方案是把返回緩衝區宣告為靜態變數:

static char retbuf[20];

總結:若要返回字串或其它集合,則返回指標必須是靜態分配的緩衝區,或者呼叫者傳入的緩衝區,或者用malloc()獲得的記憶體,但不能是區域性(自動)陣列。

當你呼叫free()的時候,傳入指標指向的記憶體被釋放,但呼叫函式的指標值可能保持不變,因為c的按值傳參語義意味著被調函式永遠不會改變引數的值。嚴格的說,被釋放的指標值是無效的,對它的任何使用,即使沒有解參照,也可能帶來問題,儘管作為一種實現質量的表現,多數實現都不會對無傷大雅的無效指標使用產生例外。

補充:free()過後的指標也叫做「野指標」,建議free()過後立即將指標置為null,詳細原因請看「為什麼free(re)過後re不為null呢

?」。calloc(m, n)本質上等價於:

p = malloc(m * n);  

memset(p, 0, m * n);

填充的全是零,因此不能確保生成有用的空指標值或浮點零值,free()可以安全的用來釋放calloc()分配的記憶體。

你可以用下面這樣的兩步方法迫使巨集既字串化又擴充套件:

#define str(x) #x  

#define xstr(x) str(x)

#define op plus

char *opname = xstr(op);

這段**把opname置為「plus」而不是「op」。

總結:在使用符號粘接操作符##連線兩個巨集的值(而不是名字)時也要採用同樣的「迂迴戰術」。

如果源和目的引數有重疊,memmove()提供***的行為。

而memcpy()則不能提供這樣的保證,因此可以實現的更加有效率。

如果有疑問,最好使用memmvoe()。

只需要重複百分號:%%。\%不行,因為\是編譯器的轉義字元,而這裡我們的問題最終是printf的轉義字元。

跟fgets()不同,gets()不能被告知輸入緩衝區的大小,因此不能避免緩衝區的溢位。標準庫的fgets()函式對gets()作了很大的改進,儘管它仍不完善。如果真的可能輸入很長的行,還是需要仔細思考,正確處理。

#define isnan(x)    ((x) != (x))
c99提高isnan(), fpclassify()及其它一些類別的函式。

附:標準c函式庫的源**:

gnu工程有乙個完全實現的c函式庫(

)有個使用指標的方法:

int x = 1;  

if(*(char *)&x == 1)

printf("little-endian\n");

else

printf("big-endian\n");

另外乙個可能是用聯合。

用mktime()或localtime()(注:如果tm_hour的值為0,要注意dst(夏時制)的調整);或者zeller的congruence;或者這個由tomohiko sakamoto提供的優雅的**:

int dayofweek(int y, int m, int d)  /* 0 = sunday */  

; y -= m < 3;

return (y + y/4 - y/100 + y/400 + t[m - 1] + d) % 7;

}

《你必須知道的495個C語言問題》一導讀

你必須知道的495個c語言問題 你可能在酒吧或聚會上有這樣的經歷,有人跟你打賭讓你做一些看似簡單,但最後卻限於人體特質或物理規律而根本無法完成的事情。跟你打賭的人知道,他挑戰的人越多,他持續獲勝的可能性就越大,因為這些特質或規律雖然十分隱晦,卻是相當穩定 可以 的。同樣,如果你讓很多人來完成乙個複雜...

你必須知道的495個C語言問題,學習體會二

這是本主題的第二篇文章,主要就結構體,列舉 聯合體做一些解釋 現代c語言程式設計 結構化的基石,diy時代的最好代言人,是物件導向程式設計中類的老祖宗。我們很容易定義乙個結構體,比如學生 struct student 在使用該結構體的地方都可以使用stu st 代替 struct student s...

你必須知道的495個C語言問題,學習體會一

c語言作為一門古老的語言,其靈活性和容易出錯都讓人 又愛又恨,書籍 你必須知道的495個c語言問題 使用問答的形式,告訴讀者 c語言使用的各個方面的知識,包括一些冷知識等。以下,我要摘錄和整理些 我認為比較重要的知識進行分享。1.關於int與long,眾所周知,c語言標準沒有規定標準型別的大小,特別...