因为二维数组(如int arr3)内存连续,类型退化为int ()[4],而非int ;后者指向不连续的指针数组,结构不同,强行转换会导致类型警告和运行时错误;正确方式是用int ()[n]传参。

为什么 int** 不能直接接收二维数组
因为二维数组(如 int arr[3][4])在内存中是连续存储的,它本质是“一段连续的 int”,类型是 int[3][4],退化为指针时是 int(*)[4](指向含 4 个 int 的数组的指针),不是 int**。后者通常指向“指针数组”,每个元素是独立分配的 int*,内存不连续,结构完全不同。强行用 int** 接收会触发类型不匹配警告,运行时访问极易越界或读错地址。
正确传参方式:用指向数组的指针 int (*)[N]
这是最直接、零拷贝、类型安全的做法,前提是列数 N 在编译期已知:
void process(int (*mat)[4], int rows) {
for (int i = 0; i int arr[3][4] = {};
process(arr, 3); // ✅ 自动退化为 int (*)[4]
- 函数形参必须写明第二维大小(
[4]),否则编译失败 - 调用时传数组名即可,无需取地址(
&arr是int(*)[3][4],类型不匹配) - 支持原生下标访问,无性能损失
列数未知时:用一维指针 + 手动计算索引
当列数只有运行时才知道(比如函数要泛化处理任意宽的矩阵),就得放弃二维语法,用 int* 加偏移计算:
void process_flat(int* data, int rows, int cols) {
for (int i = 0; i int arr[3][4] = {};
process_flat(&arr[0][0], 3, 4); // ✅ 取首元素地址,转成 int*
- 必须确保传入的是真正连续的二维数组(非
int**动态分配的“伪二维”) -
&arr[0][0]是标准写法;(int*)arr虽然等效但类型转换略显生硬 - 所有下标访问都需手动展开,易错点集中在
i * cols + j是否写反、是否越界
别踩 int** 的坑:什么情况下它才真能用
int** 只适用于“指针的指针”这种动态分配的非连续结构,例如:
int** mat = new int*[3]; for (int i = 0; i
- 这种布局每行内存独立,
mat[i]是单独new出来的地址,mat[i] + 1不等于mat[i+1] - 无法用
&mat[0][0]得到整个数据块首地址——根本不存在连续块 - 混用
int (*)[N]和int**参数会导致未定义行为,编译器通常不会帮你拦住
真正容易被忽略的是:C++ 没有“通用二维数组指针”类型,传什么取决于你手上数据的真实内存布局。选错类型,轻则结果错,重则段错误,而且问题常在特定尺寸下才暴露。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











