數組名是首地址,指針變量存地址。將數組首地址賦給指針,即可用指針以多種方式訪問數組元素。本文系統對比一維數組的四種訪問形式、指針遞增陷阱,並引入二維數組地址結構。
int a[10], *ptr;
ptr = a; // 或 ptr = &a[0];
a 是數組首地址,&a[0] 是首元素地址,兩者數值相同。ptr 成為指向數組 a 的指針變量。
| 形式 | 語法 | 含義 | 示例代碼 |
|---|---|---|---|
| 1. 指針+偏移(地址法) | ptr+n / a+n | 元素 a[n] 地址 (&a[n]) | scanf("%d", ptr+n); printf("%d", *(ptr+n)); |
| 2. 解引用偏移 | *(ptr+n) / *(a+n) | 元素 a[n] 值 | printf("%d", *(a+n)); |
| 3. 指針下標法 | ptr[n] | 等價 *(ptr+n) | scanf("%d", &ptr[n]); printf("%d", ptr[n]); |
| 4. 指針遞增法 | *ptr++ | 取值後指針後移1元素 | scanf("%d", ptr++); printf("%d", *ptr++); |
所有形式輸出結果完全一致,本質均為指針算術。
for(n=0;n<10;n++) scanf("%d", ptr++); // 輸入後 ptr 指向 a[10] (越界)
for(n=0;n<10;n++) printf("%d", *ptr++); // 輸出垃圾數據!
// 必須重置:ptr = a;
關鍵: *ptr++ 先解引用當前元素,**後**將指針加 sizeof(int)。循環結束後指針指向數組尾後,**必須重置**才能再次正確訪問。
int a[3][4]; // 3行4列,按行優先連續存放
地址關係:
a / &a[0][0] / a[0]:均為首地址(第0行首地址)。a[n]:第 n 行首地址。&a[n][m]:第 n 行第 m 列元素地址。a[n] + m 等價 &a[n][m]。
int *ptr = a; // ptr 指向 a[0][0]
for(i=0;i<3;i++)
for(j=0;j<4;j++)
scanf("%d", ptr++); // 依次訪問 12 個元素
ptr = a; // 重置
for(i=0;i<3;i++) {
for(j=0;j<4;j++) printf("%4d", *ptr++);
printf("\n");
}
將二維數組視為一維連續內存,單指針 ptr++ 掃描所有元素,極其高效。
for(i=0;i<3;i++)
for(j=0;j<4;j++)
scanf("%d", a[i]+j); // a[i] 是行首地址,+j 得元素地址
for(i=0;i<3;i++) {
for(j=0;j<4;j++) printf("%4d", *(a[i]+j));
printf("\n");
}
保留行索引 i,語義更清晰,適合需要行列邏輯的場景。
徹底理解指針與數組的地址等價關係、四種訪問形式的本質統一、指針遞增的副作用、二維數組行優先佈局,是從「會用數組」進階到「玩轉內存」的關鍵一步。