C Primer Plus(二)
重讀C Primer Plus ,查漏補缺
重讀C Primer Plus,記錄遺漏的、未掌握的、不清楚的知識點
分支和跳轉
1、ctype.h標頭檔案裡包含了一些列用於字元判斷的函式,包括判斷數字、大小寫字母,控制字元,可列印字元等一些列函式以及轉換字母大小寫的字元對映函式。
2、C99標準要求編譯器支援至少127層if-else巢狀。
3、包含iso646.h標頭檔案,可以使用and、or、not代替 &&、||、!,這是為了適應世界各地的鍵碟符號。
字元輸入/輸出和輸入確認
4、 緩衝區分為完全緩衝和行緩衝,完全緩衝在緩衝區滿時清空,行緩衝在遇到換行時清空,例如檔案輸入(完全)和標準輸入(行),緩衝區大小取決於作業系統,512和4096位元組是常見的值。
5、在多數Unix環境下,用[Ctrl+D]可以模擬產生一個檔案尾訊號,用以通知讀取標準輸入的程式已讀取完,可能這也和互動模式下Python用這個快捷鍵關閉互動模式有關。
6、Unix下的重定向運算子,輸入重定向<,輸出重定向>,兩個運算子可以組合使用。他們只可以連線可執行檔案和資料檔案,同類型不能連線,同時輸入和輸出不能重定向到一個以上的檔案。
7、同時Unix還具有追加資料運算子>>,管道運算子 |,具體用法就要參照Unix相關書籍了,這並不是C的一部分。
函式
8、注意設定遞迴的結束條件,以及指標的用法,沒有其餘需要注意的內容。
陣列和指標
9、C99標準支援初始化特定專案,如:
1 int arr[10] = {1,2,3,[5]=31}
未被初始化的專案都將被置為0。
10、 對於一個二維(多維)陣列arr[n][m]而言,arr+1和arr[0]+1是不同的。
11、對於二維陣列來說,arr時地址的地 址,要取兩次值才可以得到通常的數值。
1 這裡添一句題外話,在《C Primer Plus》第五版中,P267程式清單10.15的程式碼和程式碼輸出 2 結果不一致,兩個二維陣列的下標寫反了。 3 在輸出中: 4 zippo[1][2] 應寫為 zippo[2][1] 5 *(*(zippo+1)+2) 應寫為 *(*(zippo+2)+1)
12、int (*arr)[2] 表示指向一個包含兩個int的陣列的指標;
int *arr[2] 表示包含兩個int型別指標的陣列,出現這個差別的原因在於運算子的結合性。
arr[m][n] 等價於 *(*(arr+m)+n)
13、對於N維陣列,int arr[][10][20][30] 等價於 int (*ar) [10][20][30]
第一個方括號中可以不寫,因為它將被認為是一個數組的指標,後面的數字則確定了具體的資料型別,必須填寫。
14、C99標準支援變長陣列,指維數可以用變數宣告的陣列,並不是維數可變,在函式引數中省略變數名時,應用星號代替維數,int sum(int, int, int [*][*]);
15、C99標準支援複合文字,例如(int [2])= {10, 20},因為是匿名變數,所以必須是宣告時立刻使用,或者用指標儲存其地址。目前還沒用過這個特性。
字串和字串函式
16、用陣列的方法初始化一個字串時,陣列尾部未被使用的記憶體全部被初始化為\0,並不是只有字串結尾處被賦值\0。
17、char *m3 = "hello" 和 char m3[] = "hello" 在宣告上作用幾乎相同。不同的是,陣列名是常量,無法修改其值,但指標是可以的。
1 這裡又發現一處本書的錯誤: 2 P285中間偏下的位置 const char *m3[] = "....省略....." 應該為 3 const char *m3 = "....省略....."
18、對於char arr[m][n] 和 char* arr[] 來說,前者是一個字串陣列,也是一個矩形陣列,而後者是一個字串型別的指標陣列,它其實也是矩形的,但其中儲存的是地址,而字串儲存在程式用來儲存常量的那部分,所以沒有被浪費掉的空間,但是這些串是不能被修改的。
19、fgets函式相比gets更加安全,可以指定讀入的資料長度,遇到換行符也同樣讀入,同時可以指定從哪一個檔案讀入,標準輸入UNIX下可指定為stdin。
20、對於命令列中的引數,作業系統預設以空格劃分一個個字串,UNIX也允許使用引號把多個單詞集中在一個引數裡,例:
1 repeat "I am hungry" now
21、字串轉換為整數,常用atoi,還有atof,atol。複雜的有,strtol,strtoul,strtod,可以找出第一個非數字字元,並且可以轉換相應進位制,不常用。
儲存類、連結和記憶體管理
22、對於具有檔案作用域的變數(即通常所說的全域性變數),static表明其連結型別維內部連結,只有這個檔案中的函式可以訪問這個變數。
23、五種儲存類:
儲存類 | 時期 | 作用域 | 連結屬性 | 宣告方式 |
自動 | 自動 | 程式碼塊 | 空 | 程式碼塊內 |
暫存器 | 自動 | 程式碼塊 | 空 | 程式碼塊內,使用關鍵字register |
具有外部連結的靜態 | 靜態 | 檔案 | 外部 | 所有函式之外 |
具有內部連結的靜態 | 靜態 | 檔案 | 內部 | 所有函式之外,使用關鍵字static |
空連結的靜態 | 靜態 | 程式碼塊 | 空 | 程式碼塊內,使用關鍵字static |
24、對於下列程式碼:
1 double *ptd = (double*) malloc (30 * sizeof(double))
在C中,型別指派(double*)是可選的,但在C++中必須有,因此使用型別指派可使程式由C移植到C++更容易。
25、分配記憶體時,calloc函式接收兩個引數,並且會將申請到的塊記憶體全部置為0,但有些硬體系統浮點值並不全部用0表示。
26、一個位於*前的const使得指向的資料成為常量,位於*後的const使得指標成為常量。
27、restrict只能用來修飾指標,且這個指標指向的資料塊由該指標初始且唯一訪問,編譯器會將根據這一點,對多條涉及這個指標的運算進行優化。
28、在C99標準下,有一些舊關鍵字可以出現在新的位置。
1 void fun(int a1[const], int a2[restrict], int n) 2 void fun(double ar[static 20])