sizeof(arr)/sizeof(arr[0])仅适用于编译期大小已知的栈/全局数组;函数参数中数组退化为指针导致sizeof失效;std::array.size()零开销且类型安全;new分配的数组无长度信息,须手动保存;传参时应显式传递长度或用std::span。

用 sizeof 算静态数组长度,但只对栈上定义的数组有效
编译期已知大小的数组(比如 int arr[5]),sizeof(arr) / sizeof(arr[0]) 是最常用也最可靠的写法。它本质是让编译器把整个数组当做一个连续内存块来算总字节数,再除以单个元素字节数。
常见错误现象:void func(int arr[]) { return sizeof(arr); } 这里返回的是指针大小(通常是 8),不是数组长度 —— 因为函数参数里的 arr[] 实际退化为 int*,sizeof 失效。
- 只适用于函数内部定义的局部数组、全局数组、或
constexpr数组 - 不能用于
new int[n]或std::vector,它们不是“编译期固定大小”的类型 - 注意
sizeof(arr[0])比硬写sizeof(int)更安全,能适配不同元素类型
std::array 直接调 .size(),零开销且类型安全
如果你能控制数组声明方式,优先用 std::array<int></int> 替代裸数组。它本质是封装了固定大小栈数组的类模板,.size() 是 constexpr 成员函数,编译期求值,无运行时成本。
使用场景:需要把数组传进函数又不想丢长度信息;配合泛型算法(比如 std::sort(arr.begin(), arr.end()));想避免 C 风格数组隐式退化问题。
立即学习“C++免费学习笔记(深入)”;
-
std::array的大小必须在编译期确定,不能写std::array<int n></int>(n是变量) - 和裸数组一样不支持动态扩容,但它提供了
.data()接口,可兼容需要int*的旧代码 - 别误用
std::size(arr)(C++17 起)—— 它对std::array和原生数组都有效,但对指针无效,容易掩盖退化问题
动态分配的数组(new)没有内置长度,必须自己记
int* p = new int[n]; 分配出来的是一段原始内存,C++ 不保存 n。你无法从 p 本身反推出长度,任何试图用 sizeof(p) 或类似技巧的行为都是未定义的。
为什么这样做:因为 new 返回的是纯指针,底层只管理内存块起始地址,元信息(如长度)不在语言规范要求范围内。
- 唯一可靠做法是:分配时把
n存在另一个变量里,例如size_t len = n; int* p = new int[len]; - 更推荐直接换成
std::vector<int></int>,它的.size()就是为此设计的,且自动管理内存 - 如果必须用裸指针(比如对接 C API),务必确保长度变量和指针生命周期一致,避免悬垂或误用
函数传参时怎么安全带长度信息
裸数组作为参数传入函数时,长度信息必然丢失。这不是缺陷,而是 C++ 继承自 C 的设计事实。所以所有“安全传递”的方案,本质都是显式把长度作为额外参数带上。
常见错误现象:写 void process(int arr[]) 然后在函数里用 sizeof(arr),结果永远是 8(64 位系统下指针大小)。
- 最直白:加一个
size_t len参数,void process(int arr[], size_t len) - 更现代:用
std::span<int></int>(C++20),它轻量包装指针+长度,支持范围 for,且能从std::array或std::vector构造 - 避免用
int arr[5]这种带数字的形参 —— 数字只是文档作用,编译器不检查,也不影响实际行为
真正容易被忽略的点是:同一个项目里混用裸数组、std::array、std::vector 和 std::span 时,长度获取方式完全不同,而且编译器几乎不会帮你发现传错类型导致的长度误读。盯紧变量声明类型,比记住每种写法更重要。











