《C and Pointers》是 C 語言進階經典。本文提煉書中關鍵知識點,涵蓋輸入處理、字符編碼、指針聲明、const 語義、表達式求值、指針運算、數組與指針關係、字符串操作、位段、動態記憶體等核心主題。
int ch;
while ((ch = getchar()) != EOF && ch != '\n'); // 正確:ch 為 int 接收 EOF
getchar() 返回 int,EOF 為負值(通常 -1),char 會截斷導致誤判。舊標準支援鍵盤缺少字符的替代輸入:
| ??= | # | ??( | [ | ??/ | \ |
| ??) | ] | ??' | ^ | ??! | | |
| ??< | { | ??> | } | ??- | ~ |
現代編譯器默認關閉,可用 -trigraphs 啟用。
char 是否為 signed 由實現定義。signed char / unsigned char 提高明確性,但需注意庫函數參數多為 char*,強制轉換可能產生警告。int *a; // a 是指向 int 的指針
int *b, c, d; // 僅 b 是指針,c/d 是 int
int (*p)[10]; // p 是指向 int[10] 的指針(數組指針)
int *p[10]; // p 是 int* 陣列(指針數組)
int (*f)(); // f 是函數指針,指向返回 int 的函數
int *(*f)(); // f 是函數指針,指向返回 int* 的函數
int *(*f[])(); // f 是函數指針數組
口訣:從標識符出發,先右後左,遇括號優先處理括號內。
| 聲明 | 含義 | 可修改指針? | 可修改所指值? |
|---|---|---|---|
| 指向常量的指針 | 是 | 否 | |
| 常量指針 | 否 | 是 | |
| 指向常量的常量指針 | 否 | 否 |
記憶口訣:* 左邊的 const 修飾所指類型,右邊修飾指針本身。
x = y + 3;、getchar();、a++;。printf() 返回輸出字符數,常被忽略,屬「有用的副作用」。a*b + c*d 中,三個乘法相對順序未規定,只要各乘法在相鄰加法前完成即可。c + --c、f() + g() + h()(若函數有副作用)。t1=f(); t2=g(); t3=h(); sum=t1+t2+t3;。p + n 等價 p + n * sizeof(*p)。ptrdiff_t,結果為元素個數差:(p2 - p1) == (p2 - p1) / sizeof(*p1)。| 特性 | 數組 int a[5] | 指針 int *p |
|---|---|---|
| 記憶體分配 | 編譯期分配 5 個 int | 僅分配指針變量本身 |
| 初始化 | 可用列表初始化 | 未初始化(自動變量) |
| sizeof | 整個數組大小 | 指針大小 |
| 賦值 | 不可整體賦值 | 可賦值指向任意 int |
| ++/-- | 不可修改(地址常量) | 可修改 |
數組名在表達式中退化為指向首元素的常量指針,兩例外:sizeof(arr)、&arr(得數組指針 int (*)[5])。
char s1[] = "Hello"; // 數組,內容可修改,大小 6
char *s2 = "Hello"; // 指針指向唯讀字面量區,修改 s2[i] = UB
同樣寫法「"Hello"」,上下文決定語義。
strlen 返回 size_t(無符號),strlen(x) - strlen(y) >= 0 永真(無符號下溢)。strchr/strrchr 查找單字符,第二參數為 int 但傳字符值。strpbrk 查找任一字符集合首次出現。strspn 計算前綴匹配字符集的長度;strcspn 計算前綴不匹配字符集的長度。strtok 分割字符串,會修改原串,非線程安全(內部靜態狀態),嵌套解析需用 strtok_r。
struct {
unsigned int ch : 7;
unsigned int font: 6;
unsigned int size: 19;
} CHAR;
int/signed int/unsigned int(C99 允許 _Bool)。signed/unsigned 時符號性由實現定義 → 務必顯式聲明。| 函數 | 用途 | 關鍵行為 |
|---|---|---|
| malloc(size) | 分配未初始化塊 | 失敗返 NULL,地址對齊滿足最嚴格類型 |
| calloc(n, sz) | 分配並歸零 | 等價 malloc + memset(0),大數組有開銷 |
| realloc(ptr, nsz) | 調整大小 | 可能移動塊,舊指針失效,必用返回值;ptr=NULL 等同 malloc |
| free(ptr) | 釋放 | ptr 為 NULL 安全無操作;重複釋放/釋放非堆指針 = UB |
鐵律:每個 malloc/realloc 必檢查 NULL,每個分配必配對 free,釋放後指針置 NULL 防野指針。
指針是 C 語言的靈魂,亦是最大坑源。精通《C 與指針》一書核心內容,等於掌握了 C 語言 80% 的深層機制。建議反覆研讀、實驗驗證,方能寫出正確、高效、可移植的 C 代碼。