原回答一句話道盡:「C語言的優點就是體現在指標上。所以這是必須學好的。」指標是 C 語言靈魂,掌握指標即掌握了:
| 痛點 | 本質 | 破解關鍵 |
|---|---|---|
符號混淆 * / & | 宣告 vs 運算雙重語義 | 口訣:宣告時 * 表「是指標」;使用時 * 表「取值」;& 永遠表「取址」 |
| 指標與陣列關係 | 陣列名多數場合退化為指標 | 記住:int a[10] 中 a 是 int (*)[10],退化為 int * 指向首元素;sizeof(a) == 40 非 8 |
多層指標 **、*** | 指標的指標、輸出參數、二維陣列 | 畫記憶體圖:int **p → 指向 int * → 指向 int;層層解參考 |
| 動態記憶體管理 | malloc/free、洩漏、雙重釋放、使用後釋放 | 原則:誰配置誰釋放、配置即檢查 NULL、釋放後置 NULL、Valgrind/ASan 必跑 |
| const 與指標組合 | const int* vs int* const vs const int* const | 右左法則:從變數名向右讀,再向左讀;int const *p = 指向常數整數的指標 |
void swap(int *a, int *b)for (int *p = arr; p != arr + n; ++p)strlen、strcpy、strcat 手寫版int *arr = malloc(n * sizeof(int)),支援擴容 reallocqsort 比較函數、狀態機跳轉表const 正確性:API 設計中區分「只讀參數」與「輸出參數」atomic_compare_exchange、RCUmmap(MAP_SHARED)、shm_open、跨進程同步volatile uint32_t *reg = (uint32_t *)0x400000001. 指標宣告即初始化:int *p = NULL;
2. malloc 回傳必檢查:if (!p) handle_error();
3. free 後立即置 NULL:free(p); p = NULL;
4. 陣列參數退化:void f(int a[]) ≡ void f(int *a),sizeof 失效
5. 字串字面常數唯讀:char *s = "hello"; s[0] = 'H'; // UB!
6. 指標算術以元素大小為單位:p + 1 移動 sizeof(*p) 位元組
6. 釋放非堆記憶體、重複釋放、野指標使用 → 即時崩潰或延遲災難
「指標難在『間接性』:你不再直接操作值,而是操作『值的地址』。畫圖、寫註解、用除錯器觀察記憶體,三個月後你會發現:指標其實是最直觀、最強大的工具。」