C中奇怪的输出问题

时间:2018-06-26 12:43:31

标签: c pointers

1)  #include <stdio.h>
    int main()
  {
       int a[5] = {1,2,3,4,5};
       int *ptr = (int*)(&a+1);
        printf("%d %d", *(a+1), *(ptr-1));
        return 0;
   }

输出为2 5 &a的意思是a[0]的地址,因此&a+1应该是a[1]的地址。因此ptr应该保留a[1]的地址。 *(a+1)将为2,但*(ptr-1)也将为2。我不知道它如何打印5。

4 个答案:

答案 0 :(得分:4)

此表达式很重要:&a+1。实际上是(&a)+1等于(&a)[1],它将是指向数组末尾一个元素的指针。

如果我们更“图形化”地看待它,它看起来像这样,并添加了相关的指针:

+------+------+------+------+------+
| a[0] | a[1] | a[2] | a[3] | a[4] |
+------+------+------+------+------+
^      ^                           ^
|      |                           |
|      &a[1] (equal to *(a + 1))   |
|                                  |
&a[0] (equal to a)                 |
|                                  |
&a                                 &a+1

首先,&a的类型为int (*)[5],因此对int *的强制转换将破坏严格的别名(导致未定义的行为)。

第二,由于ptr有效指向a[5],因此ptr - 1将指向a[4]

答案 1 :(得分:2)

&a不是a[0]的地址,而是a的地址。值可以相同,但类型不同。对于指针算术,这一点很重要。

在表达式&a + 1中,首先具有类型为&a的{​​{1}},即指向大小为5的数组的指针。当您向其添加1时,它实际上将添加{{ 1}}个字节到指针值。因此int (*)[5]实际上指向数组末尾的一个字节。然后,您将此表达式从sizeof(a)强制转换为&a + 1并将其分配给int (*)[5]

当您随后计算int *时,ptr运算符从*(ptr - 1)的字节值中减去1 * -,因此它现在指向数组的最后一个元素,即5,那就是打印的内容。

答案 2 :(得分:1)

&a给出数组的地址,作为 array指针int (*)[5]。这是一种指向整个数组的指针类型,因此,如果对它进行指针算术运算,+1的意思是+sizeof(int[5]),这不是您想要的。

正确的代码:

int *ptr = a+1;

值得注意的是,演员(int*)隐藏了这个错误。不要使用强制转换使您不了解的编译器错误消失!

答案 3 :(得分:1)

首先,您说过: &a表示a[0]的地址,因此&a+1应该是a [1]的地址?不,您错了。 &a表示a而不是a[0]的地址。 &a+1表示它以整个数组大小递增,而不仅仅是一个元素的大小,而a+1表示a[1]的地址。

这里

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

a的基地址为0x100

    --------------------------------------
    |   1   |   2   |   3  |   4   |   5  |
    --------------------------------------
   0x100   0x104   0x108   0x112  0x116 ..  
   LSB
    |
    a  

做事时

int *ptr = (int*)(&a+1);

ptr指向何处?首先执行(&a+1),它按整个数组大小递增,即

(&a+1) == (0x100 + 1*20) /* &a+1 here it increments by array size */
       == 0x120

所以现在ptr指向

    --------------------------------------
    |   1   |   2   |   3  |   4   |   5  |
    --------------------------------------
   0x100   0x104   0x108   0x112  0x116  0x120  
    a                                     |
                                         ptr points here

现在,当您进行打印时

printf("%d %d", *(a+1), *(ptr-1));

这里

*(a+1) == *(0x100 + 1*4) /* multiplied by 4 bcz of elements is of int type*/
       == *(0x104) /* value at 0x104 location */
       == 2 (it prints 2)

*(ptr-1)  == *(0x120 - 1*4)
          == *(0x116) /* prints value at 0x116 memory location */
          == 5

注意:-此处

int *ptr = (int*)(&a+1);
&a

类型是int(*)[5]的指针,即指向5个元素的数组的指针,但是您要转换为int*类型的指针,如@someprogrammerdude所指出的那样,它破坏了严格的别名并导致发生不确定的行为。

正确的是

int *ptr = a+1;