<p>数组名在多数上下文中自动退化为指向首元素的指针,故 int p = arr; 合法且常用;但 sizeof 和 &arr 中不退化,&arr 类型为 int()[N],而 &arr[0] 类型为 int,更清晰安全;切勿用 int* 接数组名,函数传参时引用可保留大小信息。</p>

指针直接赋值数组名就能拿到首地址
数组名在大多数上下文中会自动退化为指向首元素的指针,所以 int arr[5] = {1,2,3,4,5}; int* p = arr; 是合法且最常用的方式。这里 p 指向的就是 &arr[0],即首地址。
注意:不是所有场景都退化——sizeof(arr) 和 &arr 中,arr 仍代表整个数组类型,此时不能直接赋给普通指针。如果硬要取地址,得用 &arr[0] 或强制转换,但没必要绕路。
用 &arr[0] 显式取首元素地址更清晰
当代码可读性优先或配合模板/泛型编程时,显式写 &arr[0] 更稳妥,尤其避免和 &arr(数组整体地址,类型是 int(*)[5])混淆。
-
&arr的类型是int(*)[5],指向整个数组块,和int*不兼容 -
&arr[0]类型是int*,可直接赋给int* p - 对空数组(如
int arr[0])或 VLA,&arr[0]是唯一安全的首地址表达方式
别把指针声明成 int** 去接数组名
常见错误:看到“数组名是地址”,就写 int** p = &arr; —— 这会导致类型不匹配编译失败,因为 &arr 是 int(*)[N],不是 int**。
立即学习“C++免费学习笔记(深入)”;
真正需要 int** 的场景极少,比如你有一堆动态分配的 int*,再用指针存它们的地址。普通静态数组不需要、也不应该用二级指针来“接”首地址。
典型错误现象:error: cannot convert 'int (*)[3]' to 'int**'
数组传参时指针和引用的区别影响首地址获取
函数参数里写 void f(int* p) 或 void f(int arr[]),实际都是接收首地址;但写 void f(int (&arr)[3]) 就能保留数组大小信息,内部仍可用 &arr[0] 获取首地址。
- 前者丢失长度,
p就是裸指针,需额外传 size - 后者类型安全,
sizeof(arr)/sizeof(arr[0])可算出长度 - 两者内部访问首地址的方式一致,但后者更适合模板推导和边界检查
容易忽略的是:函数内对形参 int arr[] 取地址,仍是 &arr[0],不是 &arr —— 因为形参已退化为指针,&arr 此时等价于 &p(取指针变量本身的地址),完全不是原数组首地址。


















