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

《C 與指標》核心筆記精華:從輸入處理到動態記憶體

     編輯:關於C語言

前言

《C and Pointers》是 C 語言進階經典。本文提煉書中關鍵知識點,涵蓋輸入處理、字符編碼、指針聲明、const 語義、表達式求值、指針運算、數組與指針關係、字符串操作、位段、動態記憶體等核心主題。

1. 標準輸入與 EOF 處理

int ch;
while ((ch = getchar()) != EOF && ch != '\n');  // 正確:ch 為 int 接收 EOF
  • getchar() 返回 int,EOF 為負值(通常 -1),char 會截斷導致誤判。
  • 賦值運算符優先級低於比較運算符,故需括號。

2. 三字母詞

舊標準支援鍵盤缺少字符的替代輸入:

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

現代編譯器默認關閉,可用 -trigraphs 啟用。

3. char 符號性與可移植性

  • char 是否為 signed 由實現定義。
  • 僅使用 ASCII 範圍(0-127)保證可移植。
  • 顯式聲明 signed char / unsigned char 提高明確性,但需注意庫函數參數多為 char*,強制轉換可能產生警告。

4. 指針聲明讀法:右左法則

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 是函數指針數組

口訣:從標識符出發,先右後左,遇括號優先處理括號內。

5. const 指針完整語義

int const *p;int * const p;int const * const p;
聲明含義可修改指針?可修改所指值?
指向常量的指針是否
常量指針否是
指向常量的常量指針否否

記憶口訣:* 左邊的 const 修飾所指類型,右邊修飾指針本身。

6. 表達式語句與副作用

  • 任何表達式加分號即成語句:x = y + 3;、getchar();、a++;。
  • 表達式語句求值後丟棄結果,僅保留副作用(賦值、函數調用、自增等)。
  • printf() 返回輸出字符數,常被忽略,屬「有用的副作用」。

7. 運算符優先級與求值順序陷阱

  • 優先級決定結合方式,不完全決定求值順序。
  • a*b + c*d 中,三個乘法相對順序未規定,只要各乘法在相鄰加法前完成即可。
  • 副作用與求值順序混用 = 未定義行為:c + --c、f() + g() + h()(若函數有副作用)。
  • 解決:用臨時變量強制順序 t1=f(); t2=g(); t3=h(); sum=t1+t2+t3;。

8. 指針運算細節

  • p + n 等價 p + n * sizeof(*p)。
  • 指針相減得 ptrdiff_t,結果為元素個數差:(p2 - p1) == (p2 - p1) / sizeof(*p1)。
  • 允許比較指向數組最後元素後一位置的指針(哨兵),禁止比較首元素前位置。
  • 標準未定義有符號右移行為(算術/邏輯移位),可移植代碼應避免。

9. 數組與指針的本質區別

特性數組 int a[5]指針 int *p
記憶體分配編譯期分配 5 個 int僅分配指針變量本身
初始化可用列表初始化未初始化(自動變量)
sizeof整個數組大小指針大小
賦值不可整體賦值可賦值指向任意 int
++/--不可修改(地址常量)可修改

數組名在表達式中退化為指向首元素的常量指針,兩例外:sizeof(arr)、&arr(得數組指針 int (*)[5])。

10. 字符串字面量 vs 字符數組初始化


char s1[] = "Hello";  // 數組,內容可修改,大小 6
char *s2 = "Hello";   // 指針指向唯讀字面量區,修改 s2[i] = UB

同樣寫法「"Hello"」,上下文決定語義。

11. 字符串操作函數精要

  • strlen 返回 size_t(無符號),strlen(x) - strlen(y) >= 0 永真(無符號下溢)。
  • strchr/strrchr 查找單字符,第二參數為 int 但傳字符值。
  • strpbrk 查找任一字符集合首次出現。
  • strspn 計算前綴匹配字符集的長度;strcspn 計算前綴不匹配字符集的長度。
  • strtok 分割字符串,會修改原串,非線程安全(內部靜態狀態),嵌套解析需用 strtok_r。

12. 位段


struct {
    unsigned int ch  : 7;
    unsigned int font: 6;
    unsigned int size: 19;
} CHAR;
  • 僅限 int/signed int/unsigned int(C99 允許 _Bool)。
  • 未指定 signed/unsigned 時符號性由實現定義 → 務必顯式聲明。
  • 分配順序(左→右或右→左)、跨邊界行為、最大寬度均與實現相關 → 嚴重影響可移植性,嵌入式外慎用。

13. 動態記憶體管理

函數用途關鍵行為
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 代碼。

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