C指针中a和a+0之间有什么区别?

4

看一下这段 C 代码。

#include <stdio.h>
int main(void)
{
    int v[3] = {1, 2, 3};
    printf("%d\n", v);
    printf("%d\n", v + 0);
    printf("%zu\n", sizeof(v));
    printf("%zu\n", sizeof(v + 0));
    printf("%zu\n", sizeof(v + 1));
    printf("%zu\n", sizeof(v + 2));
    return 0;
}

以下是其中一个输出:

-587904464
-587904464
12
8
8
8

我认为v与v+0是相同的。

它们都指向数组v[3]中的第一个元素。

因此,v和v + 0具有相同的值。

但为什么它们却无法持有相同的字节呢?(sizeof(v)和sizeof(v + 0)不同)


1
这就是为什么当“a”是一个数组时,“a+1”和“&a+1”会产生不同结果的原因。 - phuclv
你不能使用%d打印地址。你必须使用%p并将参数转换为指向void的指针。 - Jens
1个回答

9
在大多数情况下,数组标识符会衰减为指向数组第一个元素的指针。但是,在数组是sizeof运算符的操作数时,这种转换不会发生,并且运算符生成数组在字节中的大小。来自C11草案标准的§6.3.2.1 ¶3:

除非它是sizeof运算符,_Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串文字,否则类型为“类型数组”的表达式将转换为指向数组对象初始元素的类型为“类型指针”的表达式,它不是lvalue。

请注意,在C18标准中,此处已从本句中删除_Alignof运算符(讨论在此处)。
因此,sizeof(v)生成的是数组v[]的大小,即12个字节。也就是说,操作数的类型是int [3],因为该数组尚未转换为指向int的指针(如在大多数表达式中),sizeof运算符生成该类型(一个3个ints的数组)的大小(以字节为单位)。
但是通过sizeof(v + 0),表达式v + 0的类型决定了sizeof运算符所生成的结果。在表达式v + 0中,数组v[]会衰减为指向v[]第一个元素的指针,然后根据指针算术规则添加0。结果是指向int的指针(因为&v[0]本身就是指向int的指针),因此表达式v + 0的类型为int *。因此,sizeof运算符在这种情况下生成指向int的指针的大小。相似的表达式sizeof (v + 1)等也是如此。
另外,请注意,必须在首先强制转换为void *之后使用%p转换说明符打印地址,以避免未定义的行为:
printf("%p\n", (void *)v);
printf("%p\n", (void *)(v + 0));

@DavidC.Rankin -- 感谢您提供的链接;当我最初回答时,我太懒了,没有去找它,但现在我已经添加了它 ;) - ad absurdum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接