<p>C++中函数参数int arr[]实际等价于int* arr,数组形参在编译期必然退化为指针,sizeof返回指针大小,多维数组仅保留后续维度尺寸,需用引用、std::array或模板避免退化。</p>

函数参数声明里写 int arr[] 实际就是 int* arr
这是 C++(和 C)语言标准明确规定的:所有数组形参在编译期都会被调整为指针类型。哪怕你写成 void f(int arr[10]) 或 void f(int arr[100]),编译器也只当它是 void f(int* arr)。方括号里的数字纯粹是注释,不参与类型检查,也不影响生成的代码。
所以你在函数内部对 arr 做任何操作,它都只是个普通指针——sizeof(arr) 返回的是指针大小(通常是 8),arr + 1 跳过一个 int,不是跳过整个数组。
sizeof 在函数内失效,是因为退化已经完成
退化发生在“求值上下文”中,而函数调用正是典型场景:传入的 arr 已经不再是数组对象,而是首元素地址。此时 sizeof(arr) 测的是指针变量本身占多少字节,不是原数组。
- 在定义处:
int data[5]; sizeof(data)→ 20(假设int是 4 字节) - 在函数内:
void f(int data[]) { sizeof(data); }→ 8(64 位平台)
这不是编译器 bug,也不是优化行为,而是语言规则强制要求的语义转换。一旦跨过函数边界,类型信息就不可逆地丢失了。
立即学习“C++免费学习笔记(深入)”;
多维数组只保留后续维度,第一维必然退化
比如 void g(int mat[][10]),这里的 mat 类型实际是 int (*)[10](指向含 10 个 int 的数组的指针),不是 int**。第二维尺寸 10 被保留,因为指针算术需要知道每行多宽;但第一维尺寸完全消失,mat + 1 会跳过整行(40 字节),而不是单个元素。
常见误判是以为 mat[i][j] 能自动推导行数,其实不能——i 越界时编译器不会报错,运行时可能读到非法内存。
想保留数组长度?必须绕过退化机制
退化是默认行为,但你可以主动阻止它:
- 用引用:
void h(int (&arr)[5])—— 此时arr是数组别名,sizeof(arr)仍是 20,且模板推导也能得到int[5] - 用
std::array:void i(const std::array<int>& arr)</int>—— 类型安全,自带.size() - 用模板推导数组长度:
template<size_t n> void j(int (&arr)[N])</size_t>—— 编译期拿到N
手写 arr + sizeof(arr)/sizeof(*arr) 在函数内永远别用——只要 arr 是形参,这行代码就等价于 ptr + 8/4,结果是未定义行为。
退化本身不难理解,真正容易出问题的是那些“看起来像数组、其实是指针”的隐式切换——它不报错、不警告,只在越界或长度计算错误时才暴露,而且调试器里看内存地址还一模一样。


















