sizeof(arr) / sizeof(arr[0])仅对编译期已知大小的栈/全局数组有效;传入函数时数组退化为指针,sizeof返回指针大小而非数组长度,结果错误。

sizeof(arr) / sizeof(arr[0]) 只在定义处有效
这是最常被误用的方法。它只在数组作为局部变量在函数内定义时才可靠,因为此时 sizeof 能拿到真实内存大小。一旦数组退化为指针(比如传入函数、作为返回值、或用 new 分配),sizeof(arr) 就变成指针大小(通常是 8 字节),结果完全错误。
常见错误现象:int arr[5] = {1,2,3,4,5}; void f(int a[]) { cout —— 输出不是 5,而是 1(x86_64 下常为 8/8=1)。
- 适用场景:仅限栈上定义的原生数组,且未发生数组到指针的隐式转换
- 不适用:函数参数、全局数组(若声明为 extern)、
std::vector、动态分配数组(new int[n]) - 注意:对
char[]字符串字面量也有效,但需小心末尾\0是否计入
用 std::array 替代 C 风格数组
std::array 是类型安全、长度内建的替代方案,.size() 成员函数永远可靠,且不退化为指针。
示例:std::array<int> arr = {1,2,3,4,5}; cout </int>
- 优势:编译期知道长度,支持范围 for、STL 算法,无额外运行时开销
- 限制:长度必须是编译期常量;不能直接从函数返回 C 风格数组再转成
std::array - 兼容性:C++11 起可用,现代项目应优先考虑
动态数组(new / malloc)必须自己记长度
C++ 中用 new int[n] 或 malloc 分配的内存没有元信息,系统不保存长度。你必须显式保存 n,别指望靠地址推算。
错误做法:int* p = new int[10]; size_t len = *(size_t*)((char*)p - sizeof(size_t)); —— 这是未定义行为,不同编译器/分配器实现完全不同。
- 正确做法:始终配套维护一个
size_t len变量,或封装进结构体/类 - 更推荐:改用
std::vector<int></int>,其.size()安全、高效、语义清晰 - 性能影响:
std::vector在绝大多数场景下与裸指针性能无差异(小对象优化、无虚函数、连续内存)
字符串字面量和 char 数组要区分 '\0'
对 char arr[] = "hello";,sizeof(arr) 是 6(含 \0);但 strlen(arr) 返回 5。二者语义不同:sizeof 是分配字节数,strlen 是首 \0 前字符数。
- 使用场景:
sizeof适合拷贝整个缓冲区(如memcpy);strlen适合文本处理 - 坑点:如果数组未以
\0结尾(比如手动填充),strlen会越界读取,导致未定义行为 - 安全替代:C++20 起可考虑
std::string_view,构造时明确指定长度,避免依赖\0
真正麻烦的是那些“看起来像数组、其实是指针”的边界情况——比如函数参数、模板推导、extern 声明。这时候硬算 sizeof 不仅得不到长度,还会掩盖设计缺陷。把长度作为独立参数传入,或者换用容器,通常比纠结怎么“取长度”更省事。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











