C语言中数组指针的奇怪行为

4

这是我编写的一个代码,旨在测试/理解数组中指针的行为。

int main(void){
    int a[4];
    memset(a, 0, sizeof(a));
    printf("%x %x\n",a,&a);
}
Output of the above program on my machine:
bfeed3e8 bfeed3e8

我不明白为什么变量a和&a的值是相同的。据我了解,&a应该给出存储变量a的内存地址。

这种行为的解释是什么?


此外,可能是数组地址的重复。 - Mr Lister
8个回答

9

&a给你的是a的地址。而a给你的是a,因为它是一个数组,所以会衰变成指向a的指针。

或者严谨地说,它会衰变成指向a[0]的指针。


那就是我说的!等等,那不是我说的,我只是让它看起来像是我说的。抱歉。 - Mr Lister
1
严谨和不严谨之间的区别(也就是a衰减和&a结果之间的区别)在于类型。数组与其第一个元素具有相同的地址,但&a的类型为int(*)[4],而&a[0]的类型为int* - Steve Jessop
如果您指定 a,那么被推入堆栈的任何内容的类型是什么? - Mr Lister
1
@MrLister 你的堆栈是有类型的吗? - unwind
还在思考反驳的话,稍等片刻。 - Mr Lister
@Mr. Lister:如果您将a指定为vararg,则会将int *放在varargs应该放置的位置(您希望这是堆栈,但请检查平台的ABI)。非常有可能,指向相同地址的两个具有不同类型的指针具有完全相同的表示形式。这实际上并不是标准要求普通对象表示的,尽管对于varargs可能是如此--我不记得是否允许将所有指针varargs读取为void *,如果是这样,那么即使它们通常不这样,所有指针也必须具有与varargs相同的表示形式。 - Steve Jessop

4
在这种情况下,数组名a将衰减为指向其第一个元素的指针。您是指?
printf("%x %x\n",a[0],&a);

1
表达式&a的类型是int (*) [4](指向4个元素的int数组的指针),并且计算为数组对象的地址;在这方面,指向数组的指针与指向其他任何东西的指针类似。
奇怪的是如何处理表达式a。除非它是sizeof或一元&运算符的操作数,或者是用于在声明中初始化另一个数组的字符串字面值,类型为“N元素数组的T” 的表达式将被替换为/转换为/“衰减”为类型为T * (指向T的指针),其值是数组中第一个元素的地址。由于数组的地址和数组中第一个元素的地址相同,因此两个表达式都产生相同的value,但它们的types不同。

0

数组的名称也指向它所持有的内存块的起始位置。没什么大不了的。

以下这些都是等价的:

printf("%x\n",a);
printf("%x\n",&a);
printf("%x\n",&a[0]);

0
在指针上下文中,数组会衰变为指针。因此,a 会衰变为数组第一个字节的地址,而 &a 根据定义是第一个字节的地址。你可能想要在 printf 中使用 *aa[0] 而不是 &a

0

数组名"a"指向数组的第一个元素。

为了更好地理解:

  *(a + 2) is same with a[2].

0

在 C 语言中,数组名字,在这个例子中是 a,被视为一个标签,并代表着数组的地址。对它应用取地址符号(ampersand)会被解释成同样的意思。

函数指针也有类似的问题。如果 func 是一个指向函数的指针,你可以使用 func()(*func)() 来调用该函数。

还有一些间接引用语法的情况,需要特殊处理。


0
int test[10]         = test is pionter as well as &test

如果您想操作除base之外的元素,请使用&test[4]

顺带一提

&test = @test[0] = test

所有指向基本元素的指针


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