讀C陷阱與缺陷筆記

2021-08-14 07:09:45 字數 3090 閱讀 1670

1.字元與字串

(1)用單引號引起的乙個字元實際上代表乙個整數,整數值對應於該字元在編譯器採用的字符集中的序列值。

eg:對於採用ascii字符集的編譯器而言,'a'的含義與0141(八進位制)或者97(十進位制)嚴格一致。

(2)用雙引號引起的字串,代表的是乙個指向無名陣列起始字元的指標,該陣列被雙引號之間的字元以及乙個額外的二進位制值為零的字元『\0』初始化。

eg:printf("hello world\n");與char hello = ; printf(hello);相一致。

2.函式宣告

(1)任何c變數的宣告都由兩部分組成:型別以及一組類似表示式的宣告符。宣告符從表面上看與表示式有些類似,對他求值應該返回乙個宣告中給定型別的結果。

eg: float f;  float *pf;  float *g(); float (*h)();

(2)型別轉換符:只需要把宣告中的變數名和宣告末尾的分號去掉,再將剩餘的部分用乙個括號整個「封裝」起來即可。

eg:  宣告:float (*h)();

型別轉換符:(float (*)())

(3)函式指標: float (*fp)();                         呼叫:  (*fp)();

(4)將常數0轉型為「指向返回值為void的函式的指標」型別: (void (*)())0

(5)獲取變數的型別:只需要在變數宣告中將變數名去掉即可

3.優先順序

(1)任何乙個邏輯運算子的優先順序低於任何乙個關係運算子

(2)移位運算子的優先順序比算術運算子要低,但是比關係運算子要高

4.函式呼叫

(1)c語言要求:在函式呼叫時即使函式不帶引數,也應該包括引數列表。

eg:f();

5.指標與陣列

(1)c語言中只有一維陣列,而且陣列的大小必須在編譯期就作為乙個常數確定下來。然而,c語言中陣列的元素可以是任何型別的物件,當然也可以是另外乙個陣列。

(2)對於乙個陣列,我們只能夠做兩件事:確定該陣列的大小,以及獲得指向該陣列下標為0的元素的指標。

(3)宣告乙個陣列:int a[3];

(4)任何指標都是指向某種型別的變數。

eg:int *ip;   表明ip是乙個指向整型變數的指標

eg:int calendar[12][31];

int (*monthp)[31];

monthp = calendar;

int *dayp;

dayp = *monthp;

(5)在c語言中,字串常量代表了一塊包括字串中所有字元以及乙個空字元(『\0』)的記憶體區域的位址。

(6)在c語言中,我們沒有辦法可以將乙個陣列作為函式引數直接傳遞。如果我們使用陣列名作為引數,那麼陣列名會立刻被轉換為指向該陣列第1個元素的指標。因此,將陣列作為函式引數毫無意義。所以,c語言中會自動地將作為引數的陣列宣告轉換為相應的指標宣告。

(7)複製指標並不同時複製指標所指向的資料。

(8)出於**文件化的考慮,常數0這個值經常用乙個符號來代替:#define null 0

(9)當常數0被轉換為指標使用時,這個指標絕對不能被解除引用。換句話說,當我們將0賦值給乙個指標變數時,絕對不能企圖使用該指標所指向的記憶體中儲存的內容。

(10)「欄杆錯誤(差一錯誤)」的解決技巧:用第乙個入界點和第乙個出界點來表示乙個數值範圍。

入界點:包括在取值範圍之中

出界點:不包括在取值範圍之中

eg:x>=16  且  x<38   16為入界點,38為出界點  長度即為:38-16=22

常用例子:

建議的做法: int a[10],i;

for (i = 0; i < 10; i++)

a[i] = 0;

不建議的做法:int a[10], i;

for (i = 0; i <= 9; i++)

a[i] = 0;

(11)陣列中實機不存在的「溢界」元素的位址位於陣列所佔記憶體之後,這個位址可以用於進行賦值和比較,但是不能使用該位址的引用。

6.宣告與定義 

(1) int a; 如果其位置出現在所有的函式體之外,那麼它就被稱為外部物件a的定義。

(2)extern int a; 這個語句說明a是乙個外部整型變數,但是它包括了extern關鍵字,這就顯示地說明了a的儲存空間是在程式的其他地方分配的。

(3)建議:每個外部變數只定義一次

7.static int a; a的作用域限制在乙個原始檔中,對於其他原始檔,a是不可見的。

8.為了避免可能出現的命名衝突,如果乙個函式僅僅被同乙個原始檔中的其他函式呼叫,我們就應該宣告該函式為static。

9.保證乙個特定名稱的所有外部定義在每個目標模組中都有相同的型別,一般來說是程式設計師的責任。

eg:(1) char filename = "/etc/passwd";

extern char filename;

(2) char* filename = "/etc/passwd";

extern char* filename;

10.getchar函式在一般情況下返回的是標準輸入檔案中的下乙個字元,當沒有輸入時返回eof(乙個在標頭檔案stdio.h中被定義的值,不同於任何乙個字元)。

11.程式輸出有兩種方式:一種是即時處理方式,另一種是先暫存起來,然後在大塊寫入的方式,前者往往造成較高的系統負擔。因此c語言一般是通過庫函式setbuf來控制寫操作之前的輸出資料量。

12.在呼叫庫函式時,我們應該首先檢測作為錯誤指示的返回值,確定程式執行已經失敗,然後,在檢查errno,來搞清楚出錯原因。

13.建議:在巨集定義中最好把每個引數都用括號括起來,同樣,整個結果表示式也應該用括號括起來。

14.建議:相比起巨集定義,建議使用typedef來定義

15.null指標並不指向任何物件。因此,除非是用於賦值或比較運算,出於其他任何目的使用null指標都是非法的。

16.呼叫malloc(n)將返回乙個指標,指向一塊新分配的可以容納n個字元的記憶體,程式設計者可以使用這塊記憶體。把malloc函式返回的指標作為引數傳入給free函式,就釋放了這塊記憶體,這樣就可以重新利用了。呼叫realloc函式時,需要把指向一塊已分配記憶體的區域指標以及這塊記憶體新的大小作為引數傳入,就可以調整(擴大或縮小)這塊記憶體區域為新的大小,這個過程中有可能涉及到記憶體的拷貝。

C陷阱與缺陷 筆記

這本書很薄,看目錄感覺講的也很基礎,估計能較快看完。算是開始閱讀前陣子買的那波書的熱身吧。學過編譯原理,我們應當了解,編譯器的工作基本過程。在詞法分析中,不同編譯器的不同設定,會帶來不同的問題。雖然很是細微,但是如果出錯,可能編譯器不提示,讓人抓狂.int a 0195 int b 0215 int...

C陷阱與缺陷 筆記

fortan formula translator 公式翻譯程式語言 fibonacci 斐波那契 為什麼n 的含義是n 0,而不是n 0?a b的含義是?賦值操作符為什麼是 而不是 ascii碼 貪心原則?10是否能表示成010?單引號括起來的乙個字元表示乙個整數,雙引號括起來的乙個字元代表乙個指...

C陷阱與缺陷筆記

第一章 詞法陷阱 1.1 不同於 1.2 與 不同於 與 1.3 詞法分析中的 貪心法 1.4 整型變數 1.5 字元與字串 第二章 語法陷阱 2.1 理解函式宣告 2.2 運算子的優先順序問題 2.3 注意作為語句結束標誌的分號 2.4 switch語句 2.5 函式呼叫 2.6 懸掛 else引...