简体   繁体   English

C中奇怪的输出问题

[英]strange output issue in c

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;
   }

the output is 2 5 . 输出为2 5 &a means the address of a[0] so &a+1 should be the address of a[1] . &a表示a[0]的地址,因此&a+1应该是a[1]的地址。 So ptr should hold the address of a[1] . 因此, ptr应该保留a[1]的地址。 *(a+1) will be 2 but *(ptr-1) should also be 2. I can't understand how is it printing 5. *(a+1)将为2,但*(ptr-1)也将为2。我不知道它如何打印5。

This expression is the important thing: &a+1 . 此表达式很重要: &a+1 That is actually (&a)+1 which is equal to (&a)[1] which will be a pointer to one element past the end of the array. 实际上是(&a)+1等于(&a)[1] ,它将是指向数组末尾一个元素的指针。

If we look at it more "graphically" it looks like this, with relevant pointers added: 如果我们更“图形化地”看待它,它看起来像这样,并添加了相关的指针:

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

First of all, the type of &a is int (*)[5] , so your cast to int * will break strict aliasing (which leads to undefined behavior ). 首先, &a的类型是int (*)[5] ,因此您对int *的强制转换将破坏严格的别名(这将导致未定义的行为 )。

Second of all, since ptr is pointing, effectively, to what would be a[5] then ptr - 1 will point to a[4] . 第二,由于ptr有效指向a[5]因此ptr - 1将指向a[4]

&a is not the address of a[0] but the address of a . &a 不是的地址a[0]的,但地址a The values may be the same but the types are different. 值可以相同,但类型不同。 That is important when it comes to pointer arithmetic. 对于指针算术,这一点很重要。

In the expression &a + 1 , you first have &a which has type int (*)[5] , ie a pointer to an array of size 5. When you add 1 to that it actually adds sizeof(a) bytes to the pointer value. 在表达式&a + 1 ,首先具有类型为int (*)[5] &a ,即指向大小为5的数组的指针。当向其添加1时,它实际上将sizeof(a)个字节添加到指针值。 So &a + 1 actually points to one byte past the end of the array. 所以&a + 1实际上指向数组末尾的一个字节。 You then cast this expression from int (*)[5] to int * and assign it to ptr . 然后,您将此表达式从int (*)[5]int *并将其分配给ptr

When you then evaluate *(ptr - 1) , the - operator subtracts 1 * sizeof(int) from the byte value of ptr so it now points to the last element of the array, ie 5, and that is what is printed. 然后,当您对*(ptr - 1)求值时, -运算符从ptr的字节值中减去1 * sizeof(int) ,因此它现在指向数组的最后一个元素,即5,这就是要打印的内容。

&a gives the address of the array as an array pointer , int (*)[5] . &a将数组的地址作为数组指针 int (*)[5] It is a pointer type that points at the array as whole, so if you do pointer arithmetic with it, +1 will mean +sizeof(int[5]) which is not what you intended. 它是一种指向整个数组的指针类型,因此,如果对它进行指针算术运算,则+1表示+sizeof(int[5]) ,这不是您想要的。

Correct code: 正确的代码:

int *ptr = a+1;

Notably, the cast (int*) was hiding this bug. 值得注意的是,强制转换(int*)隐藏了该错误。 Don't use casts to silence compiler errors you don't understand! 不要使用强制转换使您不了解的编译器错误消失!

Firstly, you said: &a means the address of a[0] so &a+1 should be the address of a[1] ? 首先,您说: &a表示a[0]的地址,所以&a+1应该是a [1]的地址? No you are wrong. 不,你错了。 &a means address of a not a[0] . &a的装置地址aa[0] And &a+1 means it increments by whole array size not just one elements size and a+1 means address of a[1] . &a+1表示它以整个数组的大小递增,而不仅仅是一个元素的大小,而a+1表示a[1]地址。

Here 这里

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

lets assume base address of a is 0x100 让我们假设基址的a0x100

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

When you are doing 当你做的时候

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

Where ptr points ? ptr点在哪里? first (&a+1) performed and it got increments by whole array size ie 首先执行(&a+1) ,它的增量是整个数组的大小,

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

So now ptr points to 所以现在ptr指向

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

Now when you print like 现在,当您打印像

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

Here 这里

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

And

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

Note :- Here 注意:-这里

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

type of &a is of int(*)[5] ie pointer to an array of 5 elements but you are casting as of int* type, as pointed by @someprogrammerdude it breaks the strict aliasing and lead to undefined behavior. &a类型为int(*)[5]即指向5个元素的数组的指针,但是您要转换为int*类型,如@someprogrammerdude所指出的那样,它破坏了严格的别名并导致未定义的行为。

Correct one is 正确的是

int *ptr = a+1;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM