数组名退化为int,但&arr类型为int()[5];对重载operator&的类型须用std::addressof获取地址;传参后sizeof失效,推荐用std::array或std::vector的data()。

数组名本身就是首地址,但类型容易搞错
在 C++ 中,arr(假设 arr 是一个内置数组,如 int arr[5])直接使用时,绝大多数上下文会自动退化为指向首元素的指针,类型是 int*。但注意:它不是“指针变量”,而是“数组名”,只是在需要时隐式转换。
常见错误是误以为 &arr 和 arr 等价——它们值相同(内存地址一样),但类型不同:
-
arr→ 类型是int*(指向int的指针) -
&arr→ 类型是int(*)[5](指向整个 5 元素int数组的指针)
这在函数传参、模板推导或 sizeof 中会立刻暴露问题。比如传给期望 int* 的函数时,用 &arr 会编译失败。
用 std::addressof 获取真正地址(尤其对重载了 & 的类型)
如果数组元素类型重载了取地址运算符(比如某些自定义类),直接写 &arr[0] 可能调用的是重载版本,而非原始地址。这时应使用 std::addressof:
立即学习“C++免费学习笔记(深入)”;
#include <memory>
int arr[3] = {1,2,3};
int* p = std::addressof(arr[0]); // 安全获取首元素地址对内置类型(int、double 等)没差别,但对用户定义类型是必要防护。
- 不要写
&arr[0]代替std::addressof(arr[0])当不确定元素类型是否重载operator& -
std::addressof是 C++11 起标准库提供的兜底方案,不触发重载
传递给函数时,别依赖 sizeof(arr) 判断长度
数组传入函数后会退化为指针,sizeof(arr) 返回的是指针大小(通常是 4 或 8),不再是数组总字节数。所以不能靠它算首地址或长度。
- 函数参数写成
void func(int arr[])或void func(int* arr),实际都是int* - 若需保留长度信息,必须显式传参:
func(arr, sizeof(arr)/sizeof(arr[0]))(仅限栈上定义的数组) - 更推荐用
std::array或std::vector,它们自带.data()成员返回首地址,且长度安全可查
用 std::array::data() 或 std::vector::data() 更现代、更安全
对于新代码,优先用容器替代裸数组。它们的 data() 成员明确返回首元素地址,类型清晰,且不涉及退化问题:
std::array<int, 5> a = {1,2,3,4,5};
int* p = a.data(); // 类型是 int*, 安全可靠
<p>std::vector<int> v = {1,2,3};
int* p2 = v.data(); // v 非空时有效;v 为空时返回 nullptr注意:v.data() 在 v 为空时返回 nullptr,而裸数组没有这种运行时检查——这也是为什么容易出错。
裸数组的“首地址”看似简单,但类型退化、生命周期、传参陷阱一环扣一环;一旦混用模板、auto 或跨作用域传递,就很容易掉进隐式转换的坑里。


















