应用于数组与指针的C中的&运算符的区别

3

假设我们有以下内容:

int foo[4] = {1, 2, 3, 4};

foo 将指向数组的第一个元素。 我们可以这样做:

printf("%p", foo); // OUTPUT is some address 0xffffcc00

现在如果我们这样做:
printf("%p", &foo); // OUTPUT is the same address 0xffffcc00

在网上搜索时,我看到用于 &<array-name> 的这种语法会获取整个数组的地址。这解释了上面两个相同值的原因,因为起始元素的地址与整个数组的地址相同。

但总体来说,我的理解是 & 应该取右侧任何东西的地址。(例如,在这种情况下,它“应该”获得指向数组第一个元素的指针的地址。)

那么为什么 &foo 没有获取指针 foo 的地址呢? 如果这是C语言的异常情况,那么它是唯一的异常情况吗?还是还有其他类似的情况?


1
“为什么&foo不能获取指针foo的地址?” --> foo不是一个指针,而是一个数组。&foo不是“指向数组第一个元素的指针的地址”,而是整个数组的地址。 - chux - Reinstate Monica
请将您的无用回答编辑为此问题的附加信息。 - Yunnosch
3个回答

4

有一个普遍的误解,认为指针和数组是同一物。它们不是,但它们是相关的。

你的第一个示例是有效的:

printf("%p", foo);

因为在大多数情况下,数组会衰减成为指向数组第一个元素的指针。
其中一种不是这样的情况是,当数组是取地址运算符&的操作数时。这将给出整个数组的地址,而不仅仅是第一个元素的地址(即使值相同)。
这在C标准的6.3.2.1p3节中有详细说明:
除非它是sizeof运算符、_Alignof运算符或一元&运算符的操作数,或者是用于初始化数组的字符串字面值,否则具有“类型为数组的type”类型的表达式将被转换为具有“指向该数组对象的初始元素的type指针”类型的表达式,并且不是左值。如果数组对象具有寄存器存储类,则其行为未定义。

@Yunnosch array 本身是一个 lvalue,虽然不可更改。我引用的段落指定了何时将数组从 lvalue 转换为 rvalue,其中排除了提到的三个运算符。 - dbush
嗯,“是一个lvalue,尽管不是可修改的”,这并不符合我的“lvalue”的理解。不是说你错了,能否提供lvalue的定义链接,让我进一步了解一下? - Yunnosch
1
@Yunnosch 6.3.2.1p1 定义了 可修改的左值。基本上它意味着可以出现在赋值语句的左侧,而裸数组则不能。 - dbush
一个数组会衰变成为指向该数组第一个元素的指针。个人而言,我更喜欢说“一个数组会衰变成为该数组第一个元素的地址(在任何函数调用中都会作为指针传递)”。这显然更长,但在我看来更准确,因为它捕捉了无法对裸数组进行赋值的情况。 - Andrew Henle
1
@endolith 数值相同但类型不同。 - dbush
显示剩余4条评论

0

指针用于以替代的简易方式访问数组元素。在低级编程中,每个变量都有一个内存地址来分配。顺便说一下,数组也是一个变量名,就像标量变量一样。

与标量变量不同,数组变量具有一些特点:

  • 元素列表(序列)按照连续的内存地址分配。
  • 因此,我们可以通过使用第一个元素的地址获取所有元素。

知道了吗,数组名称==第一个元素的地址==数组的地址

(foo == &foo == &foo[0])

所以,当您尝试使用此符号foo获取元素时,最初它指向(&foo + 0),因此根据ith值,您可以逐个访问所有元素。希望这个答案会有所帮助:)


foo == &foo 就像说 42 == 42.0. 在两种情况下,数值是等价的,但类型不同。 - chux - Reinstate Monica

0

我更喜欢使用this explanation来解释“&基本上意味着“取地址运算符””这个论点。所以,数组不是指针!但是一个数组可以自动“衰变”成为一个指针。在你的情况下,它会变成&foo[0]。但是&foo是一个指向四个整数数组的指针,因为它的类型。要获取PoC,您需要在GDB下检查ptype fooptype &foo


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