数组名不是指针但可隐式转换为指针;sizeof(arr) 返回数组总字节,sizeof(p) 返回指针大小;仅当作为sizeof、&操作数或字符串初始化时数组名不退化。

数组名不是指针,但能隐式转成指针
数组名在大多数表达式中会“退化”为指向首元素的指针,但这只是隐式转换,不是它本来就是指针。比如 int arr[5],arr 本身是类型为 int[5] 的左值,不是 int*;只有在做算术、赋值给指针变量等场景下,编译器才自动把它转成 &arr[0]。
一个关键证据:对数组名取地址——&arr 的类型是 int(*)[5](指向整个数组的指针),而 &arr[0] 或 arr(退化后)的类型才是 int*。这两个地址数值相同,但类型和含义完全不同。
sizeof(arr) 和 sizeof(p) 结果不同的根本原因
sizeof 是编译期运算符,结果取决于操作数的**静态类型**,不关心运行时值。所以:
-
sizeof(arr)中arr类型是int[5]→ 结果是5 * sizeof(int)(通常是 20) -
sizeof(p)中p类型是int*→ 结果是该平台指针大小(通常是 4 或 8) - 即使写
int* p = arr;,p仍是纯指针,sizeof(p)不会“记住”它曾指向数组
注意:sizeof 对函数参数里的数组形参也失效——因为形参 void f(int a[10]) 实际等价于 void f(int* a),sizeof(a) 永远是指针大小。
立即学习“C++免费学习笔记(深入)”;
什么时候数组名不能退化成指针?
只有三种情况数组名保持原类型(不退化),此时 sizeof 才能拿到真实长度:
- 作为
sizeof的操作数(如sizeof(arr)) - 作为一元
&的操作数(如&arr) - 作为字符串字面量初始化数组时(如
char s[] = "abc";,sizeof(s)是 4,含 '\0')
其他所有地方——传给函数、参与加法、用在 if 判断里、赋值给指针变量——都会退化。这也是为什么 std::array 和 std::vector 更安全:它们把大小信息封装进类型或对象内,不会意外丢失。
容易踩的坑:用指针模拟数组时的 sizeof 误判
新手常写类似这样的代码:
void process(int* p) {
size_t n = sizeof(p) / sizeof(*p); // 错!n 永远是 1(或更糟,是 2/4/8)
// ...
}
int arr[100];
process(arr); // 传进去的是退化后的 int*
这会导致逻辑错误甚至越界访问。正确做法是显式传入长度:
- 加一个
size_t len参数 - 改用
std::span(C++20)或std::vector - 若必须用原始数组,只在定义作用域内用
sizeof(arr)/sizeof(arr[0])
真正的难点不在语法,而在于时刻意识到:数组名的“身份”在不同上下文中会切换,而 sizeof 是唯一能抓住它“本体”的工具——可惜它只在编译期有效,且极易被作用域和参数传递破坏。










