C 語言中「陣列名在大多數表達式中退化為指向首元素的指標」是核心觀念。本文從記憶體模型、指標算術、多維陣列實際結構、函數參數傳遞等面向,系統闡述陣列與指標的等價與差異,並提供實戰操作模式與避坑指南。
int a[10];
int *p = a; // ✅ a 退化為 int* (指向 a[0])
// a = p; // ❌ 錯誤:a 非左值,不可賦值
// a++; // ❌ 錯誤:a 非常數指標,不可遞增
差異關鍵:
sizeof(a) = 陣列總位元組數 (40);sizeof(p) = 指標大小 (4/8)。&a 型別為 int (*)[10] (指向整個陣列的指標);&p 為 int**。對指向陣列元素的指標 p:
p + i 指向第 i 個元素 (位址 + i * sizeof(*p)),**非**單純位址 + i。*(p + i) ≡ p[i] ≡ a[i] ≡ i[a] (利用加法交換律)。p[i] 定義即為 *(p + i),故 i[p] 合法但不建議使用。int a[12];
int *p = a;
p = a; // p 指向 a[0]
p = p + 1; // p 指向 a[1]
p++; // p 指向 a[2]
// 等價寫法
a[2] = 10;
*(a + 2) = 10;
p[-1] = 5; // 修改 a[1] (指標減法合法,前提在陣列範圍內)
int week[7][24]; // 7 個元素的陣列,每元素為 int[24]
week 退化為 int (*)[24] (指向含 24 個 int 陣列的指標)。week[i] 退化為 int* (指向第 i 列首元素)。week[i][j] ≡ *(week[i] + j) ≡ *(*(week + i) + j)。week[0][23] 緊接著 week[1][0]。int (*p)[24] = week; // p 指向 int[24] 類型
p++; // 移動到下一列 (位址 + 24*sizeof(int))
int val = p[2][3]; // 等價 week[3][3] (p 為 week+1 時)
錯誤示範:int **p = week; ❌ 型別不相容,week 非指標陣列。
void func(int a[10]); // 等價 void func(int *a);
void func(int a[][24]); // 必須指定次維度大小
void func(int (*a)[24]); // 明確指標宣告,同上
實戰建議:
int *a 或 int (*a)[N]),避免陣列語法誤導。void func(int *a, size_t n)。void alloc(int **p, size_t n) { *p = malloc(n * sizeof(int)); }。| 模式 | 配置方式 | 存取語法 | 記憶體連續性 | 適用場景 |
|---|---|---|---|---|
| 指標陣列 | int **p = malloc(r * sizeof(int*)); for(i) p[i] = malloc(c * sizeof(int)); | p[i][j] | 各列分離 | 列長不固定、需逐列釋放 |
| 單一區塊 + 指標陣列 | int *buf = malloc(r*c*sizeof(int)); int **p = malloc(r*sizeof(int*)); for(i) p[i] = buf + i*c; | p[i][j] | 完全連續 | 高效存取、單次釋放 |
| VLA (C99) | void func(int r, int c) { int a[r][c]; } | a[i][j] | 堆疊連續 | 小規模、自動釋放、C11 為選擇性 |
char *s = "abc"; 應為 const char *s,寫入導致 UB。struct { int a[10]; } s; 可整體複製 (s1 = s2),但 int *p 成員僅複製指標 (淺拷貝)。void f(int a[10]) { sizeof(a); } 回傳指標大小,非陣列大小。ptrdiff_t (元素個數差)。std::vector (C++) 或 malloc+長度參數 (C) 管理動態陣列。struct { int data[N]; } 封裝,獲得整體複製語意。void func(const int *data, size_t len) 唯讀、`void func(int *data, size_t len)` 讀寫。int ***) ,改用扁平化索引 data[i * stride + j]。結語:陣列與指標在 C 語言中「本質同一、操作等價」,關鍵在於理解**退化規則**、**指標算術以元素大小為單位**、以及**多維陣列實為巢狀陣列**。掌握這三點,即能靈活駕馭記憶體、撰寫高效且安全的 C 程式碼。