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