int a[2][3][4]; 在概念上是 2×3×4 的立方體,但在記憶體中**是一塊連續的 24 個 int 區塊**,編譯器按**行優先**順序線性排列:
a[0][0][0], a[0][0][1], ..., a[0][0][3],
a[0][1][0], ..., a[0][2][3],
a[1][0][0], ..., a[1][2][3]
a 是含 2 個元素的陣列,每個元素是 int[3][4](二維陣列)。a[0] 型別為 int[3][4],大小 3×4×sizeof(int)。a[0][0] 型別為 int[4],大小 4×sizeof(int)。a[0][0][0] 型別為 int。a 退化為指向首個二維陣列的指標:int (*)[3][4]。a + i 偏移 i * 3 * 4 * sizeof(int) 位元組。*(a + i) 即 a[i],型別 int[3][4],退化為 int (*)[4]。*(*(a + i) + j) 即 a[i][j],型別 int[4],退化為 int*。*(*(*(a + i) + j) + k) 即 a[i][j][k],型別 int。a[i][j][k] 等價於 *(a[0][0] + i*12 + j*4 + k)(假設維度 2,3,4)。位移(bytes) 0 4 8 12 16 20 24 28 32 36 40 44 | 48 ... 元素 a[0][0][0] a[0][0][1] a[0][0][2] a[0][0][3] a[0][1][0] ... a[0][2][3] | a[1][0][0] ...
每個 int 佔 4 位元組(假設 32 位系統),整個陣列佔 24×4 = 96 位元組,無任何間隙、無指標開銷。
// 方式 1:單次分配連續記憶體(最快、緊湊、適合傳遞給需連續記憶體的 API)
int (*a)[3][4] = malloc(2 * sizeof *a); // 配置 2 個 int[3][4]
// 存取:a[i][j][k] 直接可用
// 方式 2:指標陣列(非連續、靈活、每維度大小可不同)
int ***a = malloc(2 * sizeof *a);
for (int i = 0; i < 2; ++i) {
a[i] = malloc(3 * sizeof *a[i]);
for (int j = 0; j < 3; ++j)
a[i][j] = malloc(4 * sizeof *a[i][j]);
}
// 釋放需反序巢狀 free
// 方式 3:扁平化一維陣列 + 封裝存取函數(手動計算索引,極致效能)
int *a = malloc(2 * 3 * 4 * sizeof *a);
#define IDX(i,j,k) ((i)*12 + (j)*4 + (k))
a[IDX(i,j,k)] = val;
int ***a 能直接對應 int a[2][3][4]: 前者是三級指標(三次間接引用),後者是連續記憶體塊(一次計算位移)。兩者**型別不相容**,強制轉型會導致錯誤存取。void f(int a[2][3][4]) 或 void f(int (*a)[3][4]) 或 void f(int a[][3][4]) —— 必須指定**除第一維外的所有維度大小**,編譯器才能計算步長。void f(int ***a) —— 無法正確存取原陣列。sizeof(a) 在陣列定義處得整個陣列大小(96),傳入函數退化為指標後得指標大小(4/8)。同樣原理:**遞迴定義「陣列的陣列」**。int a[2][3][4][5] 是含 2 個 int[3][4][5] 的陣列。記憶體仍線性,步長遞推計算。人腦難以視覺化 4 維空間,但編譯器只做線性位移運算,**完全沒有問題**。
總結: C 三維陣列本質是**連續記憶體 + 編譯器計算步長**。理解「陣列的陣列」與指標退化規則,即可靈活運用靜態/動態多維陣列,避免型別不匹配與記憶體錯誤。