应用于数组名称的 sizeof 与指向数组第一个元素的指针

sizeof applied to the name of an array vs a pointer to the first element of the array

假设我声明int v[]={1,2,3,4,5};

我被告知 v 是指向 v 数组中第一个元素的指针。当我调用 apply sizeofv 时,它 returns 20,我知道是 5*sizeof(int),因为数组中有 5 个元素。

v+0也是指向数组第一个元素的指针,但是sizeof(v+0)是4.

为什么 sizeof(v)=20 而 sizeof(v+0)=4?

我希望 sizeof(v) 也返回 4,因为 v 是一个指针,但它不知何故还包含有关存储在数组中的元素数量的信息。对此有何解释?

I would expect that sizeof(v) also returned 4

没有.

首先,v 不是一个指针,它是一个数组。数组衰减 为指针。在 What is array decaying?

中阅读更多内容

当您调用 sizeof(v) 时,您将获得数组的大小(以字节为单位)。

20 等于 4 * 5 = 4 * N,其中 N 是数组中元素的数量。

此外请注意,在您的系统中,int 的大小为 4 个字节。

指针和数组密切相关,但并不等同。

在大多数情况下,数组的名称将衰减 指向第一个元素的指针。然而,有一些情况不会发生这种情况,特别是当数组是 sizeof 运算符的操作数时(是的,它是一个运算符,而不是函数)。

因此在表达式 sizeof(v) 中,名称 v 不会衰减,因为它是 sizeeof 运算符的操作数。结果,给出了整个数组的大小。相反,sizeof(v+0) 是不同的,因为 v+ 运算符的操作数。在这种情况下,v 实际上会衰减为指针并执行指针运算。这给出了一个 int * 类型的表达式,它是 sizeof.

的操作数

I have been taught that v is a pointer to the first element in the v array.

你被错误地教导了。 v 不是指针 - 没有 space 因为指针被具体化为数组的一部分。你得到的是这样的:

   +---+
v: | 1 | v[0]
   +---+
   | 2 | v[1]
   +---+
   | 3 | v[2]
   +---+
   | 4 | v[3]
   +---+
   | 5 | v[4]
   +---+

不是这个:

   +---+
v: |   |
   +---+
     |
     |
     V
   +---+
   | 1 | v[0]
   +---+
   | 2 | v[1]
   +---+
   | 3 | v[2]
   +---+
   | 4 | v[3]
   +---+
   | 5 | v[4]
   +---+

除非它是 sizeof 或一元 & 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式 类型 "N-element array of T" 将被转换 ("decay") 为类型 "pointer to T" 的表达式,表达式的值将是数组第一个元素的地址。

当你写 foo( v )printf( "%p\n", (void *) v) 甚至 v[i] 时, 表达式 v 是从类型“int的5元素数组”转换为"pointer to int",表达式的值与&v[0]相同。

但是,当您写入 sizeof v 时,该转换不会发生 - sizeof 计算为整个数组中的字节数 (5 * sizeof (int))。同样,表达式 &v 的类型是 int (*)[5](指向 int 的 5 元素数组的指针),而不是 int **

这就是为什么 sizeof v 产生 20,而 sizeof (v + 0) 产生 4 - 在第二种情况下,v 而不是 的操作数sizeof表达式 (v + 0)sizeof的操作数。在表达式 (v + 0) 中,v 衰减为类型 int *。请注意,如果您编写 sizeof v + 0 - sizeof 的优先级高于加法运算符 +,您将得到不同的结果,因此该表达式将被解析为 (sizeof v) + 0

sizeof v = 20 因为在您的系统中有 5 个元素,每个元素的大小为 4 字节。至此一切都正确。但是后来你提到 v 是一个指针。是这样吗?

没有。数组不同于指针。为什么会有混淆?

sizeof(v+0) 的上下文中,这将解释一下:

您可能会从标准(指针算术下)中找到两件有用的东西§6.5.6.2

For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to a complete object type and the other shall have integer type. (Incrementing is equivalent to adding 1.)

还有来自§6.5.6.7

For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

所以这里 v 衰减为指针作为 + 的操作数而不是 sizeof 运算符的操作数。事实上,当用作 sizeof 运算符的操作数时,数组 不会 退化为指针。现在 sizeof 指针变量在 yoru 系统上是 4 字节。这就是你看到的。


长话短说数组不是指针。它们不同。第二种情况可能会给您一种错误的印象,即他们是,或者即使您的老师说了,但事实并非如此。数组衰减为不使数组成为指针的指针。