数组/指针等价性(array/pointer equivalence)的现代术语是什么?
作为写过几年C的老鸟,我敢说几乎所有碰过C的开发者都绕不开这三个关于数组和指针的核心规则——而且你可能没注意到,它们根本不是三个完全独立的知识点,而是紧密关联的整体:
数组名在表达式中多数会退化为指向首元素的指针:比如你定义
int arr[10];,当你把arr赋值给指针变量int *p = arr;时,这里的arr就不再代表整个数组,而是指向arr[0]的指针。不过要记住两个关键例外:一是用sizeof(arr)时,arr仍然代表整个数组,返回的是数组的总字节数;二是&arr,这里取的是整个数组的地址,类型是int (*)[10](指向长度为10的int数组的指针)。数组下标运算符
[]对指针和数组完全适用:其实a[b]在C语言里本质就是*(a + b)的语法糖,所以不管a是退化成指针的数组名,还是真正的指针变量,都能正常使用下标运算符。比如刚才的p[2]和arr[2]是完全等价的——甚至你写2[arr]编译器也能正常处理(虽然这种写法可读性极差,没人会这么用)。函数参数里的数组声明其实是指针:当你写
void foo(int arr[])或者void foo(int arr[10])时,编译器都会把它当成void foo(int *arr)来处理——括号里的数字会被完全忽略,因为函数参数里的“数组”根本不是真正的数组,只是指针的另一种写法。新手常踩的坑就是在函数里用sizeof(arr),得到的是指针的大小,而不是原数组的大小。
这三个点其实是一脉相承的:正因为数组名在表达式中会退化成指针,所以下标运算符能对两者通用;而函数参数里的“数组”本质是指针,也是因为数组传参时会自动退化成首元素指针,干脆直接用指针声明来简化规则。
内容的提问来源于stack exchange,提问作者Steve Summit

