因为数组形参会退化为指针,sizeof(arr) 返回指针大小而非数组长度;必须显式传入长度参数才能正确获取数组元素个数。

为什么 sizeof 在函数内对形参数组返回的是指针大小
因为 C++ 中,**数组形参会自动退化为指针**,哪怕你写成 void func(int arr[10]),编译器实际看到的仍是 void func(int* arr)。所以 sizeof(arr) 拿到的是指针长度(通常是 4 或 8 字节),不是原始数组长度。
常见错误现象:sizeof(arr) 返回 8(64 位系统下指针大小),但你传入的是 int a[5],预期是 20,结果却是 8 —— 编译不报错,但逻辑彻底错。
- 函数签名里写
int arr[]、int arr[100]或int* arr,效果完全一样,都是指针 -
sizeof是编译期运算符,它只看变量声明类型,不查运行时内存布局 - 即使开启
-Wall或/W4,这个错误也不会被警告
怎么让函数“知道”数组长度
必须显式传入长度,这是最直接、最通用的做法。C 风格函数(如 memcpy、qsort)都这么干。
void process(int arr[], size_t len) {
for (size_t i = 0; i < len; ++i) {
// 安全访问
}
std::cout << "size: " << sizeof(arr) << " (wrong!) vs len: " << len << "\n";
}
// 调用时:
int data[] = {1, 2, 3, 4, 5};
process(data, std::size(data)); // C++17 起推荐用 std::size;老标准可用 sizeof(data)/sizeof(data[0])
- 别依赖
sizeof在函数内算长度,永远传len -
std::size是 C++17 引入的安全封装,比手写sizeof(arr)/sizeof(arr[0])更可靠(支持容器) - 如果只处理栈上数组且不想改接口,可改用引用形式(见下一条)
用数组引用避免退化(限编译期已知长度)
如果数组长度在编译期固定,可以用模板 + 引用方式保留尺寸信息,此时 sizeof 才真正有效。
立即学习“C++免费学习笔记(深入)”;
template<size_t N>
void process_ref(int (&arr)[N]) {
std::cout << "size: " << sizeof(arr) << "\n"; // 输出 N * sizeof(int)
std::cout << "count: " << N << "\n";
}
// 调用:
int a[5] = {};
process_ref(a); // OK,推导出 N == 5
// process_ref(b); // b 是 int*?编译失败,类型不匹配
- 这种写法禁止传指针或动态分配数组(如
new int[5]),否则编译不过 - 模板实例化后,
arr是真实数组引用,sizeof能取到完整大小 - 若长度不固定(比如来自用户输入),这条路走不通,只能回退到显式传
len
现代 C++ 推荐:用 std::array 或 std::span
std::array 是栈上固定大小容器,自带 .size() 方法;std::span(C++20)是对任意连续内存的非拥有视图,也带 .size(),且能接原生数组、std::vector 等。
void process_span(std::span<const int> s) {
std::cout << "size: " << s.size() << "\n"; // 运行时安全获取
}
<p>int main() {
int raw[] = {1, 2, 3};
std::array<int, 3> arr = {1, 2, 3};</p><pre class="brush:php;toolbar:false;">process_span(raw); // OK
process_span(arr); // OK
// process_span(new int[3]); // 不行,new 返回的指针没长度信息}
-
std::span不拷贝数据,零成本抽象,但要求调用方确保生命周期足够长 - 如果你还在用 C++11/14,
std::array是更稳妥的选择,但只能用于编译期确定大小的场景 - 所有这些方案都绕开了“在函数内用
sizeof算形参”的死胡同 —— 因为那条路根本没出口
C++ 数组退化是底层机制,不是 bug,但容易让人误以为 sizeof 能“恢复”长度。真正可靠的长度信息,要么靠编译期约束(引用/模板/std::array),要么靠运行时显式传递(len 参数/std::span)。别在函数体内对形参用 sizeof 查大小,它只会给你指针的尺寸。


















