因为c++传数组名本质是传指针,arr在函数内退化为int*,sizeof(arr)返回指针大小而非原数组字节数,运行时无法得知元素个数;最常用安全做法是显式添加size参数。

为什么 void func(int arr[]) 拿不到数组长度
因为 C++ 传数组名本质是传指针,arr 在函数内退化为 int*,sizeof(arr) 返回的是指针大小(通常是 8),不是原数组字节数。编译器在运行时根本不知道这个指针背后连着多少元素。
最常用且安全的做法:显式加一个 size 参数
这是 C 风格和底层 C++ 代码中最直接、无歧义的方式,也和标准库(如 std::memcpy)保持一致。
示例:
void process_array(int arr[], size_t size) {
for (size_t i = 0; i
-
size_t是更合适的类型,比int更能表达“数量”语义,且与sizeof和标准容器接口对齐 - 避免用
int接长度——负数无意义,且可能溢出(比如大数组) - 调用方必须负责传对长度;传错会导致越界或漏处理,没有自动防护
用模板推导数组长度(仅限栈上数组)
适用于编译期已知大小的数组(比如局部 int arr[10]),编译器能通过模板参数推导出长度,但无法用于动态分配或函数参数本身是 int* 的情况。
示例:
template<size_t n>
void process_array(int (&arr)[N]) {
static_assert(N > 0, "Empty array not supported");
for (size_t i = 0; i // 错误调用(推导失败)
int* ptr = new int[5];
process_array(ptr); // 编译错误:不能绑定非常量引用到右值/指针
</size_t>
- 只对“真实数组”有效,对
int*、std::vector、函数返回的数组都不适用 - 函数签名暴露了数组长度,导致不同长度的数组会实例化不同函数,可能增加二进制体积
- 无法用于跨编译单元调用(模板定义需在头文件中)
改用 std::array 或 std::span(C++20 推荐)
现代 C++ 更倾向用类型安全的容器或视图替代裸数组。其中 std::span 是轻量级非拥有视图,保留原始数据位置,又自带长度信息。
示例:
#include <span>
void process_array(std::span<const int> s) {
for (int x : s) { /* 安全遍历 */ }
// s.size() 可随时取长度
}
<p>int data[] = {1, 2, 3, 4};
process_array(data); // 自动构造 span,推导长度为 4
process_array(std::span{data}); // 显式写法(C++20 起支持类模板参数推导)
</p></const></span>
-
std::span不拷贝数据,零运行时代价,兼容裸数组、std::array、std::vector的.data() - 传
std::span<int></int>比传int*+size_t更清晰,语义即“一段连续整数” - 注意:C++20 才正式引入,若项目不支持,可用
gsl::span(Guideline Support Library)作替代
真正难的不是选哪种方式,而是统一团队习惯并守住边界:裸数组 + size 参数适合系统层或兼容 C 的接口;模板推导容易让人误以为“能解决所有问题”,其实限制极多;而 std::span 看似理想,但一旦有人传了悬垂指针(比如局部数组地址逃逸),照样崩溃——它不管理生命周期。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











