二维数组名不是指向首元素的指针,而是退化为指向第一行的指针(如 int ()[4]),不能直接赋给 int;安全线性遍历需取首元素地址 &arr0 转为 int*。

二维数组名本身就是指向首元素的指针吗?
不是。比如 int arr[3][4],arr 的类型是 int[3][4],它退化为指向第一行的指针,即类型为 int (*)[4](指向含 4 个 int 的数组的指针),不是 int*。直接用 int* p = arr 会编译报错:cannot convert 'int (*)[4]' to 'int*' in initialization。
这意味着你不能像一维数组那样直接把二维数组名赋给 int* 然后 ++ 遍历——虽然内存布局是连续的,但类型系统不让你“假装”它是线性 int 序列,除非你显式转换。
怎么安全地用指针做线性遍历(按内存顺序)?
利用二维数组在内存中按行优先连续存储的特性,可以取首元素地址转成 int*,再用整数偏移遍历全部 12 个元素:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
int arr[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
int* p = &arr[0][0]; // ✅ 正确:取第一个 int 元素的地址
for (int i = 0; i
-
&arr[0][0]是最清晰、最无歧义的起点,类型就是int* - 别写
int* p = (int*)arr—— C 风格强制转换绕过类型检查,容易掩盖对齐或大小问题 - 确保你知道总元素数(
rows * cols),越界访问不会报错但行为未定义
如何用双重指针模拟“行指针 + 列指针”遍历?
如果你需要按“第 i 行、第 j 列”的逻辑操作(比如逐行处理),可以用指向每行首地址的指针数组,或直接计算行起始地址:
int arr[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
int (*row_ptr)[4] = arr; // 指向一行(4 个 int)的指针
for (int i = 0; i
-
int (*row_ptr)[4]是关键类型:括号不能少,否则变成int* row_ptr[4](指针数组) -
++row_ptr自动按行长度跳转,比手动算p + i * 4更语义清晰 - 这种写法天然适配不同列数的固定大小数组,但无法用于
int**动态分配的“伪二维数组”
为什么不能用 int** 直接指向普通二维数组?
常见误解:以为 int arr[3][4] 可以赋给 int** p。这是危险且错误的:
-
int**是“指向指针的指针”,期望内存中存的是指针序列(如int* rows[3]),而arr内存里全是int值,没有中间指针层 -
int** p = (int**)arr强制转换后,p[0]会把前 4 或 8 字节解释成一个地址,大概率非法,运行时崩 - 只有动态分配的“指针数组 + 分配的行”结构才适用
int**,和栈上声明的int[N][M]是两种内存模型
混淆这两者是段错误的高发原因,尤其在函数传参时误写 void func(int** a) 却传入 arr。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










