int a[3][4] = {
{10, 20, 30, 40},
{50, 60, 70, 80},
{90, 100, 110, 120}
};
int (*p)[4] = a; // p 指向 int[4] 類型,即 a 的首行地址
問題:解釋 (*p)[2] 與 *(p[0]+1) 為何分別輸出 30 和 20。
a (首地址) → ┌────────────────────────────────────────┐
│ a[0] (int[4]) │ a[1] (int[4]) │ a[2] (int[4]) │
├──────┬──────┬──────┬──────┼──────┬──────┬──────┬──────┤
│ 10 │ 20 │ 30 │ 40 │ 50 │ 60 │ 70 │ 80 │ ...
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
↑ ↑
p (int(*)[4]) p+1 (下一行首地址)
p[0] 等價於 *(p+0) → 取 p 指向的第一行 → 類型 int[4] → 退化為 int* 指向 10
p[0] + 1 → 指向 20
*(p[0] + 1) → 解引用 → 20
*p 解引用 p → 得到第一行 int[4](左值)
(*p)[2] → 對該數組下標 2 → 30
| 表達式 | 類型 | 值/含義 |
|---|---|---|
p | int (*)[4] | 指向「含 4 個 int 的數組」的指針(行指針) |
p[0] / *p | int[4] → 退化 int* | 第一行首元素地址(&a[0][0]) |
int* | 第一行第二個元素地址(&a[0][1]) | |
int | 第一行第二個元素值:20 | |
int[4](左值) | 第一行整個數組對象 | |
int | 第一行第 3 個元素值:30 |
p[0] 是**第一行的首地址**(指向 10 的指針),**不是**指向指針的指針。(*p)[2] 先解引用 p 得到「第一行數組」,再取下標 2。*(p[0]+1) 先取第一行首地址,偏移 1 個 int,再解引用。p+1 跳過整行(4*sizeof(int) 字節)。int **q; // 指向指針的指針(不連續,每行單獨 malloc)
int (*p)[4]; // 指向固定列數數組的指針(連續,棧上或整體 malloc)
// 切勿混淆!p 可以直接 p[0][2] 訪問,q 必須先分配行指針數組再分配每行。
理解「行指針」int (*)[N] 是掌握 C/C++ 二維數組指針的關鍵。