C++数组传参时用sizeof计算长度触发编译警告的原因
问题描述
我编写了如下代码,用于判断指定元素是否存在于同类型数组中:
#include <iostream> #include <vector> using namespace std; template <class T> bool IsIn (T a, T B[]) { bool result = false; int _size = sizeof(B)/sizeof(B[0]); for(int i = 0; i < _size; i++) if (a == B[i]) result = true; return result; } int main () { int arr1 [] = { 10, 20, 30 }; bool ee1 = IsIn(10, arr1); cout << "ee1 = " << ee1 << endl; return 0; }
我在在线编译平台选择C++选项运行上述代码,得到如下警告信息:
main.cpp: In instantiation of ‘bool IsIn(T, T*) [with T = int]’: main.cpp:19:27: required from here main.cpp:9:15: warning: ‘sizeof’ on array function parameter ‘B’ will return size of ‘int*’ [-Wsizeof-array-argument] 9 | int _size = sizeof(B)/sizeof(B[0]); | ^~~~~~~~~ main.cpp:7:19: note: declared here 7 | bool IsIn (T a, T B[]) { | ~~^~~
我不太理解上述警告信息的含义,不清楚代码存在什么问题。
问题解答
这个警告的核心原因是C++的数组退化规则:
- 当数组作为函数形参传递时,它不会保留完整的数组类型,会自动退化为指向数组首元素的指针。也就是说你函数定义里写的
T B[],本质和T* B没有任何区别,函数内部拿到的B只是一个指针,根本不知道原数组的实际长度。 - 你代码里用
sizeof(B)/sizeof(B[0])计算数组长度的写法是完全错误的:此时B是指针类型,sizeof(B)得到的是指针本身的内存大小(32位系统下为4字节,64位系统下为8字节),不是整个数组的内存大小。比如在64位环境下int占4字节,算出来的_size固定是2,循环只会遍历数组前2个元素,一旦数组更长就会出现漏判,甚至访问越界。
你可以选择以下任意一种方式修复问题:
- 方案1:传参时额外传入数组长度
手动把数组长度作为参数传给函数,避免在函数内部计算长度:
template <class T> bool IsIn (T a, T B[], int arr_len) { bool result = false; for(int i = 0; i < arr_len; i++) if (a == B[i]) result = true; return result; } // 调用时手动传入数组长度 bool ee1 = IsIn(10, arr1, sizeof(arr1)/sizeof(arr1[0]));
- 方案2:通过模板引用推导数组长度
把形参写成数组的引用类型,数组传引用时不会发生退化,编译器可以自动推导出数组长度,调用时不需要额外传参:
template <class T, size_t N> bool IsIn (T a, T (&B)[N]) { bool result = false; for(int i = 0; i < N; i++) if (a == B[i]) result = true; return result; } // 调用方式和你原来的写法完全一致 bool ee1 = IsIn(10, arr1);
- 方案3:直接使用C++标准库工具(最推荐)
不需要自己手写遍历逻辑,引入<algorithm>头文件后直接用std::find即可,原生支持普通数组、vector等所有标准序列容器,通用性更强:
#include <algorithm> // 调用示例 bool ee1 = std::find(std::begin(arr1), std::end(arr1), 10) != std::end(arr1);
内容的提问来源于stack exchange,提问作者CaTx
相关产品推荐
相关产品推荐

