Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c语言中的奇怪输出问题 1)#包括 int main() { int a[5]={1,2,3,4,5}; int*ptr=(int*)(&a+1); printf(“%d%d”,*(a+1),*(ptr-1)); 返回0; }_C_Pointers - Fatal编程技术网

c语言中的奇怪输出问题 1)#包括 int main() { int a[5]={1,2,3,4,5}; int*ptr=(int*)(&a+1); printf(“%d%d”,*(a+1),*(ptr-1)); 返回0; }

c语言中的奇怪输出问题 1)#包括 int main() { int a[5]={1,2,3,4,5}; int*ptr=(int*)(&a+1); printf(“%d%d”,*(a+1),*(ptr-1)); 返回0; },c,pointers,C,Pointers,输出为25&a表示a[0]的地址,因此&a+1应该是a[1]的地址。所以ptr应该包含a[1]的地址*(a+1)将为2,但*(ptr-1)也应为2。我不明白它是如何打印5的。&a将数组的地址作为数组指针,int(*)[5]。它是指向整个数组的指针类型,因此如果使用它执行指针算术,+1将意味着+sizeof(int[5]),这不是您想要的 正确代码: 1) #include <stdio.h> int main() { int a[5] = {1,2,3,4

输出为25
&a
表示
a[0]
的地址,因此
&a+1
应该是
a[1]
的地址。所以
ptr
应该包含
a[1]
的地址<代码>*(a+1)将为2,但
*(ptr-1)
也应为2。我不明白它是如何打印5的。

&a
将数组的地址作为数组指针,
int(*)[5]
。它是指向整个数组的指针类型,因此如果使用它执行指针算术,
+1
将意味着
+sizeof(int[5])
,这不是您想要的

正确代码:

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

值得注意的是,cast
(int*)
隐藏了这个bug。不要使用强制转换来消除您不理解的编译器错误

&a
不是
a[0]
的地址,而是
a
的地址。值可能相同,但类型不同。这对于指针算法来说很重要

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


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

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

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

int *ptr = a+1;
+------+------+------+------+------+ |a[0]| a[1]| a[2]| a[3]| a[4]| +------+------+------+------+------+ ^ ^ ^ | | | |&a[1](等于*(a+1))| | | &a[0](等于a)| | | &a&a+1 首先,
&a
的类型是
int(*)[5]
,因此对
int*
的强制转换将打破严格的别名(这将导致未定义的行为)


其次,既然
ptr
有效地指向了
a[5]
,那么
ptr-1
将指向
a[4]

首先,你说:
&a
意味着
a[0]
的地址,那么
&a+1
应该是a[1]的地址吗?不,你错了
&a
表示
a
的地址,而不是
a[0]
。而
&a+1
意味着它按整个数组大小递增,而不仅仅是一个元素大小,
a+1
意味着
a[1]
的地址

这里

假设
a
的基址为
0x100

int a[5] = {1,2,3,4,5};
当你在做

    --------------------------------------
    |   1   |   2   |   3  |   4   |   5  |
    --------------------------------------
   0x100   0x104   0x108   0x112  0x116 ..  
   LSB
    |
    a  
哪里
ptr
点?首先执行
(&a+1)
,它得到整个数组大小的增量,即

所以现在
ptr
指向

(&a+1) == (0x100 + 1*20) /* &a+1 here it increments by array size */
       == 0x120
现在,当你像

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

注意:-这里

*(ptr-1)  == *(0x120 - 1*4)
          == *(0x116) /* prints value at 0x116 memory location */
          == 5
&a
的类型为
int(*)[5]
即指向一个由5个元素组成的数组的指针,但您是按
int*
类型强制转换的,正如@someprogrammerdude所指出的,它打破了严格的别名并导致未定义的行为

正确的一个是

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

&a
a
的地址,而不是
a[0]
a
的类型是
int[5]
,因此
&a+1
向该地址添加
sizeof(a)
(即
sizeof(int)*5
)。您希望使用
int*ptr=(int*)(&a[0]+1)
使用
a+1
&a[0]+1
初始化您的
ptr
,无需强制转换。如果
ptr
的可能副本包含
a[1]
,则
*(ptr-1)
将是
1
,而不是
2
执行强制转换
(int*)(&a+1)
中断严格别名,还是随后取消引用指针
*(ptr-1)
可能会中断严格别名?@chux甚至没有尝试深入研究规范,我会说这是强制转换,因为它告诉编译器指针
&a+1
实际上不是。但不要引用我的话!:)谢谢-嗯,在回顾时,我对
&a+1
(int*)(&a+1)
、和
int*ptr=(int*)(&a+1)充满信心C11§6.3.2.3 7
对所有代码进行了明确定义。然而,这个小问题不应该让一个好的计划失去更多answer@Michi最好将这些问题作为问题而不是评论发布。强制转换从不违反严格的别名规则。规则是关于通过U类型的左值访问T类型的对象,其中T和U之间不存在某种关系。
cast(int*)隐藏了这个错误
如果我更改
int*ptr=(int*)(&a+1),会发生什么
int*ptr=*(&a+1)。因为看起来是一样的。现在
ptr
指向
int(*)[5]
并且没有强制转换。没有bug;代码正在尝试(并成功)显示
a
的最后一个元素。“正确的代码”将显示第一个元素。@Michi您不能将
int(*)[5]
隐式转换为
int*
,它们是不兼容的指针类型<代码>int*ptr=*(&a+1)是好的,除非它位于无处的中间。
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);
int *ptr = a+1;