二維數組`int a[3][4]`中,`&a[1]+1`與`a[1]+1`輸出地址不同,本質是**指針類型決定步長**。本文通過內存佈局圖解徹底釐清。
int a[3][4] = { // 3行4列,行優先連續存儲
{0, 1, 2, 3}, // 第0行:a[0][0]..a[0][3]
{10,11,12,13}, // 第1行:a[1][0]..a[1][3]
{20,21,22,23} // 第2行:a[2][0]..a[2][3]
};
// 假設首地址 a = 0x1000,int 4字節
| 表達式 | 類型 | 值(地址) | 含義 |
|---|---|---|---|
| `a` | `int (*)[4]` (指向4個int的數組指針) | 0x1000 | 整個二維數組首地址(第0行首地址) |
| `a[1]` | `int*` (退化為指向第1行首元素的指針) | 0x1010 | 第1行首元素`a[1][0]`地址 (0x1000 + 1行*4列*4字節) |
| `&a[1]` | `int (*)[4]` (指向第1行的數組指針) | 0x1010 | 第1行整體地址(數值同`a[1]`,但類型不同) |
| `a[1] + 1` | `int*` | 0x1014 | **指針算術:+1個`int`** → 第1行第2個元素`a[1][1]`地址 |
| `&a[1] + 1` | `int (*)[4]` | 0x1020 | **指針算術:+1個`int[4]`** → 第2行首地址`a[2][0]` (0x1010 + 1行*4列*4字節) |
地址: 0x1000 0x1004 0x1008 0x100C | 0x1010 0x1014 0x1018 0x101C | 0x1020 ...
值: 0 1 2 3 | 10 11 12 13 | 20 ...
└─────── a[0] (int[4]) ────────┘ └─────── a[1] (int[4]) ────────┘ └── a[2]...
a → 0x1000 (int(*)[4]) 步長 = sizeof(int[4]) = 16字節
a[1] → 0x1010 (int*) 步長 = sizeof(int) = 4字節
&a[1] → 0x1010 (int(*)[4]) 步長 = sizeof(int[4]) = 16字節
將二維數組視為**一維數組的數組**:
// 一維數組
int arr[3];
arr → 首元素地址 (int*) 步長 = sizeof(int)
&arr → 整個數組地址 (int(*)[3]) 步長 = sizeof(arr) = 3*sizeof(int)
// 二維數組同理,把「一維數組元素」換成「行(一維數組)」
int a[3][4];
a → 第0行地址 (int(*)[4]) 步長 = sizeof(int[4])
&a → 整個二維數組地址 (int(*)[3][4]) 步長 = sizeof(a)
a[1] → 第1行首元素 (int*) 步長 = sizeof(int)
&a[1] → 第1行整體 (int(*)[4]) 步長 = sizeof(int[4])
核心口訣:指針類型定步長,解引用降維度,數組名退化指向首元素,取址保持數組類型。