必须显式指定第二维大小,因二维数组传参退化为指向含n个元素一维数组的指针,编译器需n计算arri偏移;int arr[][n]与int (arr)[n]等价,均不可省略n;引用传参int (&mat)r可保留维度信息但类型严格;int*不兼容静态二维数组内存布局。

必须写明第二维大小,否则编译直接报错
所有标准写法都强制要求在形参中显式写出列数(即第二维大小),比如 int arr[][5] 合法,int arr[][] 或 int arr[3][] 都非法。根本原因在于:二维数组名传入函数时退化为“指向含 N 个元素的一维数组的指针”,而编译器需要知道 N 才能正确计算 arr[i][j] 的内存偏移 —— 即 base + i * N + j。漏掉列数,编译器连每行多长都不知道,自然无法解析下标访问。
int arr[][N] 和 int (*arr)[N] 本质等价
这两种写法生成的形参类型完全相同,都是“指向 int[N] 的指针”。区别只在可读性:
-
int arr[][N]更接近数组直觉,支持自然的arr[i][j]访问,推荐用于静态二维数组传参 -
int (*arr)[N]显式暴露指针语义,适合强调底层行为或与模板/泛型代码配合 - 二者都不能省略
N,也不能把括号写成int *arr[N](那会变成“含 N 个int*的数组”)
用引用传参能保留维度信息且避免退化
对于已知大小的静态二维数组(如 int mat[4][6]),最安全的方式是使用引用形参:void func(int (&mat)[4][6])。它不退化、不丢失尺寸、不接受隐式转换,还能在函数内用 sizeof(mat) 正确获取总字节数。但缺点也很明确:
- 函数只能接收严格匹配
[4][6]的实参,无法重用处理[3][6]或[4][5] - 如果想支持不同行数但固定列数,得靠模板:
template<size_t r> void func(int (&mat)[R][6])</size_t> - 不能用于动态分配的
int**或std::vector<:vector>></:vector>
别拿 int** 直接传静态二维数组
这是新手最常踩的坑:int mat[3][4] 是一块连续内存,而 int** 假设的是“指针数组 + 分散内存块”的结构。直接写 func((int**)mat) 并传给 void func(int** p),后续用 p[i][j] 会读到错误地址 —— 因为 p[1] 实际取的是 mat[0][4] 处的值(越界),而非 mat[1][0]。真要用 int**,必须确保实参是按指针数组方式动态分配的,且每行首地址单独存入指针数组中。
真正麻烦的地方不在语法本身,而在混淆“内存布局”和“语法糖”。静态二维数组是一整块连续内存,所有传参方式都要适配这个事实;一旦强行套用 int** 模型,底层寻址就彻底失准。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











