指標是C語言的靈魂,也是區分初學者與資深工程師的分水嶺。本文系統總結指標運算規則、函式參數傳遞、陣列關係、多維陣列映射、函式指標、字串處理等核心知識點,並附帶記憶體模型圞解,助你建立完整指標知識體系。
& (取址) 與 * (間接存取) 優先級相同,右結合*p++ 等價 *(p++):先取值,指標後移(*p)++:取值後,所指物件值加 1*p++ 中 ++ 結合 p,非 *p若 p、q 指向同一陣列元素,p - q 為兩者之間的元素個數(類型大小已內隱除以 sizeof(type))。
p + n:向後移動 n 個元素(位址增加 n × sizeof(*p))*(p + 1) 等價 p[1]僅當指向同一陣列(或同一物件內部)時,比較才有定義行為;否則屬未定義行為 (UB)。
void swap(int *p, int *q) {
int tmp = *p; *p = *q; *q = tmp;
}
// 呼叫:swap(&a, &b);
// 函式內修改 *p、*q 影響實參;但 p、q 本身(區域副本)不影響實參指標值
a 在大多數表達式中退化為 &a[0](首元素位址)a[i] 編譯器總是轉換為 *(a + i)p = a 或 p = &a[0] 皆可int a[3][4] 視為 3 個長度 4 的一維陣列:a[0], a[1], a[2]
a[i][j] → *(a[i] + j) → *(*(a + i) + j)a[i][j][k] → *(*(*(a + i) + j) + k)位址推導:
*(a + i) + j 是 a[i][j] 的位址*(*(a + i) + j) + k 是 a[i][j][k] 的位址int a[3][4]; int (*p)[4] = a; // p 指向含 4 個 int 的陣列 // p+1 指向下一行,跨度 sizeof(int[4]) = 16 位元組 // *(p+2)+3 等價 &a[2][3] // *(*(p+2)+3) 等價 a[2][3]
關鍵:int (*p)[4] 括號不可省略,否則 int *p[4] 變成指標陣列。
int *p[4]:指標陣列,常用於字串陣列 char *argv[]int **pp:指向指標的指標,多維動態陣列、命令列參數 char **argv// 宣告:回傳 int,接受兩 int 參數的函式指標
int (*funcp)(int, int);
void swap(int x, int y) { ... }
void (*p)() = swap; // 不需指定參數類型,但第一組括號不可少
應用:回調函式、策略模式、狀態機
int process(int x, int y, int (*func)(int, int)) {
return func(x, y);
}
int* create_array(int n) {
return malloc(n * sizeof(int));
}
// 呼叫端必須 free()
"hello" 存於唯讀區,型態 const char*char *p = "hello":p 指向唯讀區,不可修改內容char arr[] = "hello":堆疊陣列,可修改strlen, strcpy, strcat, strcmp, strchr, strstr 皆以指標操作字串棧區 (Stack) 堆區 (Heap) +----------------+ +----------------+ | main() 區塊 | | malloc 區塊 | | 區域變數、指標 | | 動態陣列、結構 | +----------------+ +----------------+ 資料區 (Data/BSS) 程式碼區 (Text) +----------------+ +----------------+ | 全域/靜態變數 | | 機器指令 | | 字串常數 | | 唯讀 | +----------------+ +----------------+
| 陷阱 | 正確做法 |
|---|---|
| 野指標 | 初始化為 NULL,free 後置 NULL |
| 釋放後使用 | free 即失效,不再解引用 |
| 指標越界 | 嚴格檢查索引範圍 |
| const 正確性 | 字串常數用 const char* |
| 函式指標宣告漏括號 | int (*p)(int) 而非 int *p(int) |
指標將「資料」與「位址」分離,賦予C語言直接操作記憶體的威力。掌握指標運算規則、陣列映射機制、函式指標模式,是寫出高效、靈活、系統級C程式的基石。