指向二维数组的指针必须指定列数,如int (p)[4];不能用int*,因内存布局不同;p0等价于arr0;函数参数中列数不可省略。

指向二维数组的指针声明必须带行大小
不能写成 int** p 去“通用”指向二维数组——那是指向指针的指针,和二维数组内存布局不匹配。C++ 中二维数组是连续内存块,int arr[3][4] 的类型是 int[3][4],要定义指向它的指针,必须显式写出列数(即每行元素个数)。
正确写法:int (*p)[4] = arr; —— 这表示 p 是一个指向「含 4 个 int 的一维数组」的指针。括号必不可少,否则 int *p[4] 就变成长度为 4 的指针数组了。
初始化和赋值时注意数组名退化规则
数组名在多数上下文中会退化为指向首元素的指针,但二维数组 arr 的首元素是「一行」,即 int[4] 类型,所以 &arr[0]、arr、&arr 三者值相同但类型不同:
-
arr→ 类型int(*)[4](隐式退化) -
&arr[0]→ 类型int(*)[4] -
&arr→ 类型int(*)[3][4](指向整个二维数组)
因此,int (*p)[4] = arr; 合法;但 int (*p)[4] = &arr; 编译失败——类型不匹配,需强转或改用 int (*p)[3][4]。
访问元素时别用 **p 那套逻辑
既然 p 指向的是「一行」,那么 *p 就是那一行(类型 int[4]),可再用下标访问: (*p)[2] 等价于 arr[0][2];(*p + 1) 是第二行首地址,(*p + 1)[3] 即 arr[1][3]。
常见错误:**p 试图解两次引用,但 *p 是数组类型,不是指针,**p 相当于 (*p)[0],虽能编译但语义易混淆,不推荐。
更清晰的写法:p[0][2](因 p 可按「行指针数组」理解),p[1][0] 直接访问第二行第一列。
函数参数传二维数组时本质是传指针
写函数 void func(int arr[3][4]),实际形参等价于 int (*arr)[4]。列数 4 必须指定,行数 3 可省略(int arr[][4] 或 int (*arr)[4] 都行)。
调用时直接传数组名:func(myArr);,无需取地址;若用指针变量 p,也直接传 p,不是 &p。
注意:如果函数需要处理不同列数的数组,无法用这种语法,得改用一维指针 + 手动计算偏移(int* data + rows, cols),或用 std::vector<:vector>></:vector>。
最易被忽略的点:列维度是类型的一部分,换行数不影响指针类型,但换列数就必须改指针声明——哪怕只差一个 int,int (*)[5] 和 int (*)[4] 是完全不同的类型,不能隐式转换。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











