把一维数组硬当成二维用:一次讲透 C 语言“指向数组的指针”
1. 故事开场:一段“诡异”代码
int a[] = { 10,12,30,14,50,60,71,80,90,10 };
int (*p)[4] = (int (*)[4])a;
printf("%d\n", p[1][2]); // 输出 71
短短三行,把不少同学看懵:
“一维数组怎么突然 p[1][2] 了?”、“int (*p)[4] 到底是个啥?”
下面按“理解→实战→总结”三步,一次性拆干净。
2. 拆开类型: int (*p)[4] 怎么读
| 写法 | 含义 | 加减 1 的步长 |
|---|---|---|
int *p |
指向 单个 int | sizeof(int) |
int (*p)[4] |
指向 一整行 4 个 int 的数组 | 4*sizeof(int) |
记忆技巧:
把 (*p) 看成整体,它就是“数组名”,p 自然就是“指向那个数组的指针”。
括号必不可少,否则 int *p[4] 变成“指针数组”——语义完全不同。
3. 内存布局:为什么 p[1][2] 是 7
强转之后,编译器把原内存按“每 4 个 int 一行”重新解释:
地址低 → 高
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| 10 | 12 | 30 | 14 | 50 | 60 | 71 | 80 | 90 | 10 |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
\____________ row 0 __________/ \____________ row 1 __________/ \_____ row 2 _____/
p指向 row 0p + 1跳过 一整行 → 指向 row 1 的首元素5*(p + 1)拿到 row 1 这一整行(数组)- 再
[2]取下标 → 拿到7
4. 实战场景:什么时候真有必要用“指向数组的指针”
| 场景 | 用 int (*p)[N] 的理由 |
用普通 int *p 的痛点 |
|---|---|---|
| 二维数组传参 | 列宽 N 写进类型,编译期检查;函数内仍可用 p[i][j] 语法 |
列宽靠额外参数,易传错;索引需手动 i*col+j |
| 按行迭代 | p++ 一次跳一行,代码短 |
只能 q += col,列宽一改全得改 |
示例:类型安全的传参
void foo(int (*row)[4], int n_row)
{
for (int i = 0; i < n_row; ++i)
printf("%d\n", row[i][2]); // 直接写列号 2
}
int main(void)
{
int m[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
foo(m, 3); // 列宽 4 已硬编码在类型里
}
若误传 int x[3][5],编译器立刻报错,防止越界。
5. 易混雷区: m[1] 到底是不是指针?
int m[3][4] = {...};
printf("%p\n", (void*)m[1]); // 能打印地址
printf("%d\n", *m[1]); // 输出 5
printf("%d\n", m[1][1]); // 输出 6
m[1]类型是int[4]——数组,不是指针。- 只有当数组出现在 下标运算、函数实参 等上下文时,编译器才临时把它退化成
int*。 - 因此
*m[1]等价于*(m[1]退化后的指针 + 0),拿到首元素5;
m[1][1]等价于*(m[1]退化后的指针 + 1),拿到6。 - 写
*m[1][1]会报错,因为m[1][1]已是纯int,不能再解引用。
6. 小结一张图
源码写法 实际类型 步长(+1) 常见用途
int *p int * sizeof(int) 一维/扁平缓冲区
int (*p)[4] 指向int[4] 4*sizeof(int) 二维数组按行传参、按行迭代
int *p[4] 4个int*的数组 sizeof(int*) 指针数组(完全不同)
7. 结语
- 日常元素访问直接写
m[i][j]最清爽。 - 一旦涉及“把二维数组当整体传参”或“按行遍历”,
int (*p)[N]是 唯一能把列宽写进类型、让编译器帮你查错 的利器。 - 记住“数组名先退化再运算”这条核心规则,一切指针花样都会变得透明。
希望这篇小文能把“指向数组的指针”彻底从玄学变成工具,不过是让编译器记住‘一行有多宽’罢了!”
关键词:C 语言、数组退化、指向数组的指针、二维数组传参、指针运算

浙公网安备 33010602011771号