首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

《C和指針》核心筆記精華:從輸入處理到指針運算的完整知識圖譜

     編輯:關於C

經典著作《C和指針》被公認為進階 C 語言必讀。本文提煉書中最高頻、最易錯、最實戰的知識點,構建系統性速查筆記。

1. 安全輸入處理

int ch;
while ((ch = getchar()) != EOF && ch != '\n');  // 清行緩衝
// 注意:ch 必須為 int,接收 EOF;括號保證賦值先於比較

gets() 禁用(無緩衝區溢出檢查),改用 fgets(buf, sizeof(buf), stdin)。

2. 三字母詞 - 歷史遺產

序列字符序列字符序列字符
??([??)]??!|
??<{??>}??=#
??/\??'^??-~

現代編譯器默認關閉,但維護舊代碼時可能遇見。

3. 字符類型可移植性

  • char 是否有符號由編譯器決定,不可假設。
  • 處理字符作為小整數時,顯式聲明 signed char 或 unsigned char。
  • 庫函數參數多為 char,強制轉換可能產生警告,需權衡。

4. 指針聲明讀法:從變量名向外讀

int *a;          // a 是指向 int 的指針
int *b, c, d;    // 僅 b 是指針,c/d 是 int —— 易誤區!
int const *pci;  // 指向 const int 的指針(底層 const)
int *const cpi;  // const 指向 int 的指針(頂層 const)
int const *const cpci; // 雙重 const

口訣:* 靠近類型修飾被指物,靠近變量名修飾指針本身。

5. 字符串字面量 vs 字符陣列初始化

char msg[] = "Hello";   // 陣列初始化:拷貝字符到棧上,可修改
char *msg = "Hello";    // 指向唯讀字面量:嘗試修改導致 UB

上下文決定含義:初始化陣列時為初始化列表,其他場合為字面量指針。

6. 表達式語句與副作用

  • 賦值是表達式,值為左操作數新值:r = s + (t = u - v) / 3;
  • 單獨表達式加分號即語句:y + 3;(無副作用,編譯器優化掉),getchar();(有副作用:讀取並丟棄字符)。
  • printf() 返回輸出字符數,通常被忽略,其輸出為副作用。

7. switch-case 穿透與 continue

  • 刻意穿透需加註釋 /* falls through */。
  • continue 僅作用於循環,不影響 switch;若 switch 在循環外,continue 無效。

8. 移位操作陷阱

  • 無符號右移:邏輯移位(補 0)。
  • 有符號右移:實現定義(算術/邏輯視編譯器),不可移植。
  • 移位量 < 0 或 ≥ 位寬:未定義行為,嚴禁使用。

9. sizeof 運算符

  • 編譯期計算,不求值:sizeof(a = b + 1) 不會賦值給 a。
  • 陣列名兩種例外:sizeof(arr) 返回整個陣列大小;&arr 類型為指向陣列的指針。

10. 遞增遞減副作用與求值順序

  • ++a:先增後用(值為增後值);a++:先用後增(值為增前值)。
  • ++a = 10; 錯誤:結果是右值,不可賦值。
  • 相鄰運算符優先級決定分組,非相鄰運算符求值順序未規定:f() + g() + h() 三函數調用順序不定,若有副作用必須拆分語句。
  • c + --c:未定義行為(修改與讀取無序列點)。

11. 指針運算

p + n  等價 p + n * sizeof(*p)
p2 - p1 等價 (p2 - p1) / sizeof(*p1)  // 結果為元素個數差
// 標準允許指向尾後元素的指針比較,禁止指向首前元素

12. 陣列名不是指針

  • 表達式中陣列名轉換為指向首元素的指針常量(不可修改)。
  • int a[5]; int *p = a; 合法;a++ 非法;p++ 合法。
  • 多維陣列名:int m[3][10]; → m 類型為 int (*)[10](指向 10-int 陣列的指針)。

13. 複雜聲明系統解析法:運算符優先級+括號分組

int (*f)();      // f 是函數指針,指向返回 int 的函數
int *(*f)();     // 指向返回 int* 的函數指針
int (*f[])();    // f 是陣列,元素為函數指針
int *(*f[])();   // 陣列元素為指向返回 int* 函數的指針

口訣:從變量名出發,按優先級 () [] > * > 型別,遇括號優先處理組內內容。

14. 字符串字面量指針算術

"xyz" + 1   // 指向 'y'
*"xyz"      // 'x'
"xyz"[2]    // 'z'
putchar("0123456789ABCDEF"[val % 16]);  // 十六進制字符查表

15. strlen 陷阱:無符號比較

if (strlen(x) >= strlen(y))      // 正確
if (strlen(x) - strlen(y) >= 0)  // 永真!無符號減法回繞

16. 字符串查找函數族

函數功能
strchr(s, c)查找 c 首次出現位置
strrchr(s, c)查找 c 最後出現位置
strpbrk(s, set)查找 set 中任意字符首次位置
strspn(s, set)前綴匹配 set 字符長度
strcspn(s, set)前綴不匹配 set 字符長度
strtok(s, sep)分割字符串(破壞原串、非線程安全)

17. 位段可移植性四大坑

  1. int 位段符號性實現定義。
  2. 位段寬度受限於 int 寬度(16/32 位差異)。
  3. 位分配順序(左→右 / 右→左)實現定義。
  4. 跨儲存單元邊界對齊策略實現定義。

嚴肅可移植代碼避免使用位段。

18. 動態記憶體四大函數

函數特點
malloc(n)分配 n 位元組,不初始化,失敗返 NULL
calloc(n, sz)分配 n*sz,歸零,適合陣列
realloc(p, n)調整大小,可能移動記憶體,舊指針失效
free(p)釋放,free(NULL) 安全無操作

對齊保證:malloc 返回地址滿足最嚴格類型對齊要求。

這 18 大知識點覆蓋了《C和指針》精髓的 80%,建議收藏反芻,實戰中遇到指針、字符串、記憶體疑難雜症時速查。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved