sizeof(arr)/sizeof(arr[0])仅对栈上定义的原生数组有效,函数参数中数组会退化为指针导致失效;std::size(C++17起)语义更清晰但同样不适用于指针;动态分配数组无内置长度,须自行保存。

用 sizeof 算静态数组长度,但只对栈上定义的数组有效
编译期就知道大小的数组(比如 int arr[5];),sizeof(arr) / sizeof(arr[0]) 是最常用也最可靠的写法。它本质是让编译器把整个数组当做一个连续内存块来算体积,再除以单个元素大小。
常见错误现象:sizeof(arr) 在函数参数里返回指针大小(通常是 8),导致结果永远是 1 或 0 —— 因为数组传参会退化成指针,丢失长度信息。
- 只在定义该数组的作用域内用,比如函数内部直接定义的数组
- 不能用于
new int[5]、std::vector或函数形参中的数组名 - 注意类型一致性:
sizeof(arr[0])比硬写sizeof(int)更安全,避免改类型后漏改
std::size(C++17 起)更简洁,但同样不适用于指针
std::size 是标准库提供的包装函数,底层还是靠 sizeof 实现,语义更清晰,可读性略好。但它和手写 sizeof 一样,依赖数组类型未退化。
使用场景:你用的是 C++17 或更新标准,且确定数组没被当作指针传递。
立即学习“C++免费学习笔记(深入)”;
- 写
std::size(arr)比sizeof(arr)/sizeof(arr[0])少出错,尤其对复杂类型(如struct数组) - 对
std::array、std::vector也有效,但行为不同:std::vector返回当前元素个数(运行时),而原生数组仍是编译期计算 - 如果误用于指针(比如函数参数),编译失败(SFINAE 友好),比运行时出错更容易发现
函数里怎么安全拿到数组长度?别传裸数组,改用引用或容器
一旦数组作为参数传进函数,sizeof 和 std::size 都失效。这不是技巧问题,是 C++ 类型系统的根本限制。
最容易踩的坑:写一个通用函数,试图用模板 + sizeof 自动推导长度,却忘了模板实参推导对数组退化无能为力。
- 推荐方案:用数组引用传参,例如
template<size_t n> void foo(int (&arr)[N])</size_t>,此时N可被推导,std::size(arr)也能用 - 更现代做法:直接用
std::array<int></int>或std::vector<int></int>,前者长度编译期固定,后者用.size()获取运行时长度 - 绝对避免:在函数内部对形参做
sizeof运算 —— 它永远不是你想要的“元素个数”
动态分配数组(new[])根本没有内置长度,必须自己记
int* p = new int[10]; 分配后,C++ 不保存这个 10。语言层面没有机制从 p 反查长度,sizeof(p) 是指针大小,std::size(p) 编译不过。
性能影响:有人想用 operator new[] 的实现细节去“偷看”头部长度字段,这属于未定义行为,不同编译器/平台结果不一致,调试器都可能显示错乱。
- 唯一可靠方式:分配时把长度存在配套变量里,比如
int* p = new int[n]; size_t len = n; - 更安全替代:用
std::vector,它内部封装了长度管理,.data()还能拿到原始指针 - 如果必须用裸
new[],记得delete[]时也得靠自己存的长度,别指望运行时补救
真正麻烦的地方不在怎么算,而在于什么时候“不能算”——数组一离开定义它的作用域,或者一变成指针,所有编译期技巧就全部失效。这时候硬要找“万能函数”,不如花两秒改成 std::array 或 std::vector。










