函数参数写 int arr[] 实际上传的是指针,编译器自动降级为 int*,sizeof(arr) 返回指针大小而非数组长度,因此不能用 sizeof 计算元素个数;正确做法是额外传长度参数、用 std::vector 或模板推导。

函数参数写 int arr[] 实际上传的是指针
很多人以为 int arr[] 是把整个数组“复制进”函数,其实编译器会自动把它降级为 int*。这意味着你传进去的永远是首地址,sizeof(arr) 在函数内永远是 4 或 8(指针大小),不是数组总字节数。
所以别指望在函数里用 sizeof(arr)/sizeof(arr[0]) 算长度——它一定错。
- 正确做法:额外传一个
size_t n参数表示元素个数 - 或者改用
std::array<int n></int>(编译期定长)或std::vector<int></int>(运行期可变) - 如果坚持用原生数组,调用时必须显式告诉长度:
foo(arr, 5);
用 std::vector 是最安全、最常用的选择
除非有极端性能要求或嵌入式限制,否则直接用 std::vector 接收一维数组数据,既避免越界风险,又支持动态大小和范围遍历。
示例:
void process(const std::vector<int>& v) {
for (int x : v) { /* 安全遍历 */ }
// v.size() 可靠返回当前长度
}</int>
- 传参务必用
const std::vector<int>&</int>,避免拷贝开销 - 不推荐
std::vector<int></int>值传递,尤其数据量大时 - 如果函数要修改内容,去掉
const,但保留引用
想保留 C 风格数组接口?用模板推导长度
如果你非要写形如 void foo(int arr[]) 但又想自动知道长度,唯一靠谱办法是模板 + 引用:
template <size_t n>
void foo(int (&arr)[N]) {
// 这里 N 就是数组长度,类型安全,编译期确定
for (size_t i = 0; i <ul>
<li>只能接收真正的栈上数组,比如 <code>int a[7]; foo(a);</code>
</li>
<li>不能接收 <code>int* p = new int[7]; foo(p);</code> —— 编译不过</li>
<li>不能接收函数返回的局部数组(返回栈内存地址本身就不合法)</li>
</ul>
<h3>常见错误:把指针当数组传进函数后乱用 <code>sizeof</code>
</h3>
<p>典型翻车现场:</p>
<pre class="brush:php;toolbar:false;">void bad_func(int arr[]) {
size_t n = sizeof(arr) / sizeof(arr[0]); // ❌ 永远是 1(x86_64 下常为 8/4=2)
for (int i = 0; i <p>这种写法在小数组上偶尔“碰巧”不出错,但本质是未定义行为。一旦数组实际长度小于推导出的 <code>n</code>,就踩内存。</p>
- 检查编译器警告:
-Wall通常会提示 “sizeofon array parameter will return size of ‘int *’” - 静态分析工具(如 clang-tidy)也能捕获这类误用
- 真要用原始数组,就老老实实传长度,别偷懒
C++ 里没有“传数组”的语法糖,所有看似传数组的操作,背后都是指针或模板实例化。最容易被忽略的点是:函数内无法仅凭参数类型还原出原始数组长度,必须靠外部显式提供或编译期绑定。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











