代码输出 - C语言中 & 的行为

3

我发现了一段输出结果让我无法理解的代码。这段代码是:

int main() 
{       
  int a[] = {1, 2, 3, 4, 5, 6};   

  int *ptr = (int*)(&a+1); 
  printf("%d ", *(ptr-1) ); 
  return 0; 
} 

上述代码的输出结果为6,但我认为应该是1。请解释为什么会是6。

整数占用2个字节。&a+1 只会在内存地址中向前移动一个字节...应该是 &a + sizeof(int),基本上是这样的。 - Marc B
这是技术上未定义的行为,因为您正在从不兼容的指针进行转换,应该是 int *ptr = *(&a+1); - this
1
@MarcB 不,那会指向超出范围的位置。 - this
@MarcB:int 最终是16位。但它也可以更多。对于典型的32位CPU,它大多数时候是32位(4个八位字节)。 - too honest for this site
4个回答

3
在你的问题中,“&a”是整个数组a[]的地址。如果我们将&a加1,我们会得到“a[]的基地址+sizeof(a)”这个值被强制转换为int *。因此ptr指向6后面的内存。ptr被强制转换为“int *”,并打印出*(ptr-1)的值。由于ptr指向6后面的内存,所以ptr - 1指向6。

在C语言中,数组名称(除了在sizeof运算符中)给出第一个元素的地址。将1添加到此地址会给出地址加上数组具有的类型大小。 - Deepak
返回已翻译的文本:即第二个元素 - Deepak
@DeepakTiwari:自动将数组转换为指针有更多的例外情况。请参见标准。实际上,这包括了你在回答中提到的原因。 - too honest for this site

2

&a 是数组 a 的地址。将其加上 1 将使其增加到数组之后的一个位置(增加 24 字节)。转换运算符 (int*)&a+1 转换为指向 int 类型的指针。ptr-1 仅会将 ptr 减少 4 字节,因此它是数组 a 的最后一个元素的地址。对 ptr - 1 进行解引用将给出最后一个元素,即 6


1
有趣的是,&aa在内存中具有相同的地址。区别在于它们的类型以及它们如何反映到指针算术中。很好的答案(看不出任何理由对其进行负投票)。 - Grzegorz Szpetkowski
1
@GrzegorzSzpetkowski; 这是我关于&aa的解释。 - haccks
1
@GrzegorzSzpetkowski详细说明:“&aa具有相同的_value_”。&a没有地址。 - chux - Reinstate Monica

0

是的,因为a是一个类型为int[6]的数组。因此,&a给出了类型int (*)[6]。它不是指向int的指针,而是指向int数组的指针。

所以,&a + 1将指针增加了一个数组大小,指向数组的最后一个元素之后。

然后,在ptr中取地址并执行-1,将地址减少sizeof(*ptr),即sizeof(int),这会给出数组中最后一个元素的地址。

最后,对该地址进行解引用,您将得到最后一个元素的值6。成功。


0

因为(int*)(&a+1)将整个数组作为基本类型,并在地址上增加了一个整个数组的大小,即增加了24个字节。

当你执行ptr-1时,由于ptr的类型是int,它只会减去4个字节。 在进行指针运算时要记住指针的类型非常重要。


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