如果数组类型的表达式(例如数组名称)出现在更大的表达式中,并且它不是 & 或 sizeof 运算符的操作数,则数组表达式的类型从“T的N元素数组”到“指向T的指针”,表达式的值是数组中第一个元素的地址。
简而言之,数组名不是指针,但在大多数情况下,它被视为就像它是一个指针。
编辑
回答评论中的问题:
如果我使用 sizeof,我是否只计算数组元素的大小?那么数组“head”也占用空间,包含长度和指针信息(这意味着它比普通指针占用更多空间)?
创建数组时,唯一分配的空间是元素本身的空间;没有为单独的指针或任何元数据实现存储。给定
char a[10];
你在记忆中得到的是
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
表达式 a 指的是整个数组,但没有object a 与数组元素本身分开。因此,sizeof a 为您提供了整个数组的大小(以字节为单位)。表达式&a 为您提供数组的地址,与第一个元素的地址相同。 &a 和 &a[0] 之间的区别在于结果的类型1 - 第一种情况下的char (*)[10] 和第二种情况下的char *。
当你想要访问单个元素时,事情变得奇怪了——表达式a[i]被定义为*(a + i)的结果——给定地址值a,偏移量i元素(不是字节) 从该地址并取消引用结果。
问题在于a 不是指针或地址——它是整个数组对象。因此,C 中的规则是,只要编译器看到数组类型的表达式(例如 a,其类型为 char [10])并且该表达式不是 sizeof 的操作数或一元 & 运算符,该表达式的类型被转换(“decays”)为指针类型(char *),表达式的值是数组第一个元素的地址。因此,表达式 a 与表达式&a[0] 具有相同的类型和值(并且通过扩展,表达式*a 具有与表达式a[0] 相同的类型和值)。
C 派生自一种称为 B 的早期语言,在 B 中,a是一个独立于数组元素 a[0]、a[1] 等的指针对象。Ritchie 想要保留 B 的数组语义,但他不想弄乱存储单独的指针对象。所以他摆脱了它。相反,编译器将在翻译过程中根据需要将数组表达式转换为指针表达式。
请记住,我说过数组不存储有关其大小的任何元数据。一旦该数组表达式“衰减”为指针,您所拥有的只是一个指向单个元素的指针。该元素可能是一系列元素中的第一个,也可能是单个对象。没有办法根据指针本身知道。
当您将数组表达式传递给函数时,函数接收到的所有内容都是指向第一个元素的指针 - 它不知道数组有多大(这就是为什么 gets 函数如此威胁并最终从图书馆中删除)。要让函数知道数组有多少元素,您必须使用标记值(例如 C 字符串中的 0 终止符),或者必须将元素数量作为单独的参数传递。
- 这*可能*影响地址值的解释方式 - 取决于机器。