int arr3 不能传给 void func(int*),因前者是连续内存块、退化为 int()[4] 类型,后者期待指向指针的指针;正确方式是用带列数的引用 void func(int(&arr)3) 或指针 void func(int(*arr)[4])。

为什么 int arr[3][4] 传给 void func(int**) 会报 cannot convert
因为 int[3][4] 是连续内存块,底层是 int* 类型的首地址;而 int** 表示“指向指针的指针”,期待的是一个 int* 数组(比如每行首地址组成的数组)。两者内存布局完全不同,编译器拒绝隐式转换。
常见错误现象:error: cannot convert 'int (*)[4]' to 'int**' —— 注意错误里出现的 int (*)[4],这正是二维数组退化的类型(指向含 4 个 int 的数组的指针),不是 int**。
- 别用
int**接固定大小的 C 风格二维数组 - 如果真要动态行数+列数,得自己构造
int**(malloc 每行 + 一个指针数组),但那已不是原数组 -
std::vector<:vector>></:vector>虽灵活,但内存不连续,和原int[3][4]仍不兼容
正确传参写法:用引用或指针带列数维度
C++ 允许函数参数保留数组列数信息,关键是要把第二维(列数)作为类型一部分写死。编译器靠它算偏移,才能正确解引用 arr[i][j]。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 推荐用引用:
void func(int (&arr)[3][4])—— 类型安全,不退化,sizeof正确,且禁止传错大小的数组 - 也可用指针:
void func(int (*arr)[4])—— 更接近 C 风格,调用时直接传数组名,arr[i][j]仍可用 - 若行列都不固定,改用一维视图:传
int*加两个size_t参数(如func(arr[0], rows, cols)),在函数内用ptr[i * cols + j]访问
用 std::array 或 std::vector 怎么避免这个问题
std::array 是栈上固定大小容器,类型包含维度,传参无衰减;std::vector 是堆上动态数组,需配合 data() 和尺寸手动管理。
示例对比:
void take_array(std::array<std::array<int, 4>, 3>& arr); // ✅ 完全匹配 void take_vector(const std::vector<std::vector<int>>& v); // ✅ 但非连续内存 void take_flat(const std::vector<int>& v, size_t rows, size_t cols); // ✅ 连续,需额外尺寸
注意:std::vector<:vector>></:vector> 每行是独立分配的,不能用原二维数组地址初始化;想零拷贝接入旧数组,只能选 std::array 或裸指针 + 尺寸。
容易被忽略的坑:模板推导和 auto 的行为
写模板函数时,auto 或模板参数若没显式约束,可能意外退化成指针,丢失维度信息。
比如:
template<typename T>
void bad_func(T arr) { /* arr 是 int(*)[4],但 T 被推为 int(*)[4],不是你想要的通用类型 */ }更稳妥的写法:
- 用引用模板:
template<size_t r size_t c> void good_func(int (&arr)[R][C])</size_t> - 或加
static_assert校验维度 - 避免对数组参数用
auto,它会退化成指针,失去长度信息
列数必须出现在类型中,这是 C++ 数组语义的硬性要求——漏掉它,编译器就只剩瞎猜。


















