




数组名不是指针但可隐式转换为指针;sizeof(arr) 返回数组总字节,sizeof(p) 返回指针大小;仅当作为sizeof、&操作数或字符串初始化时数组名不退化。
数组名在大多数表达式中会“退化”为指向首元素的指针,但这只是隐式转换,不是它本来就是指针。比如 int arr[5],arr 本身是类型为 int[5] 的左值,不是 int*;只有在做算术、赋值给指针变量等场景下,编译器才自动把它转成 &arr[0]。
一个关键证据:对数组名取地址—— &arr 的类型是 in(指向整个数组的指针),而 
&arr[0] 或 arr(退化后)的类型才是 int*。这两个地址数值相同,但类型和含义完全不同。
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) 永远是指针大小。
只有三种情况数组名保持原类型(不退化),此时 sizeof 才能拿到真实长度:
sizeof 的操作数(如 sizeof(arr))& 的操作数(如 &arr)char s[] = "abc";,sizeof(s) 是 4,含 '\0')其他所有地方——传给函数、参与加法、用在 if 判断里、赋值给指针变量——都会退化。这也是为什么 std::array 和 std::vector 更安全:它们把大小信息封装进类型或对象内,不会意外丢失。
新手常写类似这样的代码:
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 是唯一能抓住它“本体”的工具——可惜它只在编译期有效,且极易被作用域和参数传递破坏。