sizeof不能直接用于函数参数中的数组,因为形参会退化为指针,sizeof(arr)返回指针大小而非原数组字节数,导致sizeof(arr)/sizeof(arr[0])计算错误。

sizeof 不能直接用于函数参数里的数组
很多人写 sizeof(arr)/sizeof(arr[0]) 在函数里算元素个数,结果总是错的——因为形参 arr 实际是退化成指针,sizeof(arr) 返回的是指针大小(通常是 4 或 8),不是原数组字节数。
典型错误场景:
void foo(int arr[]) {
std::cout << sizeof(arr) << "\n"; // 输出 8(64 位系统),不是数组总字节
}- 只有在定义数组的作用域内(比如局部数组、全局数组、函数内声明的数组)才能用
sizeof正确求长度 - 传入函数后,除非用引用或模板保留类型信息,否则无法恢复数组长度
- C 风格字符串(
char[])同理,sizeof对形参无效
用模板推导数组长度最安全
让编译器在编译期推导数组类型,避免退化。这是 C++11 起推荐的做法:
template<typename T, size_t N>
constexpr size_t array_size(T (&)[N]) {
return N;
}调用时直接传数组名(不能是表达式或指针):
立即学习“C++免费学习笔记(深入)”;
int a[5] = {1,2,3,4,5};
std::cout << array_size(a) << "\n"; // 输出 5- 函数参数写成
T (&)[N]表示“对 T 类型、长度为 N 的数组的引用”,类型完整保留 -
constexpr确保编译期计算,零开销 - 不支持动态分配内存(如
new int[5]),只适用于栈上或静态数组
std::array 比裸数组更靠谱
如果可以改用标准容器,std::array 自带 size() 成员函数,语义清晰且类型安全:
std::array<int, 5> a = {1,2,3,4,5};
std::cout << a.size() << "\n"; // 输出 5
// 传入函数也不会退化
void bar(const std::array<int, 5>& a) {
std::cout << a.size(); // 仍是 5
}-
std::array是聚合类型,sizeof依然有效,但优先用.size() - 长度是类型的一部分,不同长度的
std::array类型不同,编译期检查更强 - 注意:不能用
std::array接收 C 风格数组,二者类型不兼容
运行时数组(new/malloc)没法用 sizeof
堆上分配的数组没有长度元信息,sizeof 对指针返回的是指针本身大小,和所指内容无关:
int* p = new int[10]; std::cout << sizeof(p) << "\n"; // 输出 8,不是 40
- 必须额外保存长度(比如用
std::vector,或自己维护一个size_t len) -
std::vector的.size()是唯一合理选择;裸指针 + 长度变量容易出错,不建议手动管理 - 别试图通过地址差值或 magic number 反推长度——不可靠,且违反抽象原则
真正要小心的不是怎么写 sizeof,而是搞清数组是否还保有类型信息;一旦退化成指针,就永远失去了长度。


















