因为函数参数中数组名退化为指针,sizeof(arr)返回指针大小(如64位系统为8),而非原数组长度;只有通过数组引用const t(&arr)[n]或std::array才能保留大小信息并安全获取长度。

为什么 void func(int arr[]) 里 sizeof(arr) 是 8 而不是数组真实大小
因为 arr 在函数形参中根本就不是数组类型,而是自动退化为 int* 指针。C++ 标准规定:除 sizeof、&、[]、typeid 四种上下文外,数组名都会隐式转成指针。函数参数就是典型的“退化上下文”,所以无论你写 int arr[] 还是 int* arr,编译器看到的都是指针——sizeof(arr) 返回指针大小(x86_64 下为 8),和原始数组长度完全无关。
用 const T (&arr)[N] 引用传参强制保留长度
这是唯一能在编译期拿到数组长度、支持模板推导、且不拷贝数据的安全方式。引用不会触发退化,类型信息完整保留。
template<size_t n> void process(const int (&arr)[N]) { static_assert(N > 0); /* N 就是长度 */ }</size_t>- 调用时必须传**具名数组变量**,不能传指针或临时数组字面量(如
{1,2,3}) - 对
char字符串尤其有用:template<size_t n> void print(const char (&s)[N])</size_t>能安全获取N-1作为字符串长度(含\0) - 缺点:无法接受动态分配数组、
std::vector或运行时长度未知的缓冲区
用 std::array 替代裸数组,一劳永逸
std::array 是类型安全的固定长度容器,不退化、有 .size()、可拷贝、支持范围 for,且零开销(底层仍是栈上裸数组)。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
void process(const std::array<int>& arr) { std::cout </int>- 模板泛化写法:
template<size_t n> void process(const std::array<int n>& arr)</int></size_t> - 注意:不能用
std::array接收 C 风格数组,二者类型不兼容;若需兼容旧接口,仍得靠引用传参或指针+长度 - 比裸数组多一个类型名开销,但换来编译期检查、迭代器支持和语义清晰性
什么时候还必须用指针+长度?
系统 API、C 库交互、动态内存(new int[n])、或需要处理不同长度输入的通用逻辑,都绕不开 T* ptr, size_t len 组合。
- 务必把
len声明为size_t(无符号),避免有符号/无符号比较警告 - 在函数入口立即校验:
if (!ptr || len == 0) return;,防止空指针或零长访问 - 不要用
sizeof(ptr)/sizeof(*ptr)计算长度——这永远错,只对栈上具名数组有效 - 如果调用方是
std::vector,优先用vec.data(), vec.size(),而非取地址首元素再算长度
真正容易被忽略的是:引用传参和 std::array 只解决“已知编译期长度”的场景;一旦涉及 malloc、new、外部输入或 C 接口,退化就无法避免——这时长度必须由人来保证,而不是靠语言机制。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










