指針陣列與二維陣列在語法上相似,但記憶體佈局、存取方式、靈活度截然不同。本文從定義、記憶體模型、優缺點三個維度徹底釐清兩者區別。
int a[10][20]; // 真正的二維陣列
int *b[10]; // 指針陣列(10個指針)
a[10][20]int 空間(10×20)a[0][0], a[0][1], ..., a[0][19], a[1][0], ...a[i][j] ≡ *(*(a + i) + j),編譯器自動計算偏移sizeof(a) = 200 * sizeof(int)b[10]10 * sizeof(int*))二維陣列 a[3][4]: 指針陣列 b[3](每行長度不同): ┌─────────────────────┐ ┌─────────┐ │ a[0][0] a[0][1] ... │ │ b[0] ───┼──► ┌──┬──┬──┐ │ a[1][0] a[1][1] ... │ │ b[1] ───┼──► ┌──┬──┬──┬──┐ │ a[2][0] a[2][1] ... │ │ b[2] ───┼──► ┌──┬──┐ └─────────────────────┘ └─────────┘ 連續記憶體塊 分散的記憶體塊
// 二維陣列靜態初始化
int a[2][3] = {{1,2,3}, {4,5,6}};
// 指針陣列初始化(需先有行資料)
int row0[] = {1,2,3};
int row1[] = {4,5};
int *b[2] = {row0, row1}; // 第二行只有2個元素
| 特性 | 二維陣列 | 指針陣列 |
|---|---|---|
| 記憶體連續性 | 完全連續 | 行間不連續 |
| 行長度 | 固定 | 可變(鋸齒) |
| 分配時機 | 編譯期/棧上 | 執行期/堆上 |
| sizeof 結果 | 總大小 | 僅指針陣列大小 |
| 參數傳遞 | 退化為指針 | 傳遞指針陣列 |
| 釋放管理 | 自動 | 需手動逐行 free |
// 二維陣列:必須指定列數
void func_arr(int arr[][20], int rows);
// 指針陣列:雙重指針
void func_ptr(int **arr, int rows);