指针和数组混淆

我们有

int a[5]={10, 20, 30, 40, 50}; 

我想知道以下两个代码段是如何做的?

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

如果我们有

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

应该是什么结果?

所有问题都来自于使用&a ,它是一个指向“五个整数数组”的指针,因此指针算法(当你考虑地址时)被sizeof(a) “缩放”(可能是例如20如果int是4个字节,并且编译器不需要填充用于对齐目的 – 合理的假设,当然远非确定。

所以,之后

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

ptr是指向内存地址“sizeof(a)大于地址a”的int的指针, t类似于“sizeof(a)小于a的地址”。 因此…:

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

应该是什么结果?

很可能是分段违规,否则20后跟两个完全任意的整数值。 由于ptrtint指针,因此它们的-1+1的地址算术缩放不会补偿在&a上完成&a (内存地址的缩放是由sizeof(int)而不是sizeof(a) !),因此ptr-1t+1指向(涉嫌;-) int s,它们分别是“在一个结束后的几个int ”和“在a开始之前的几个int ”。

没有办法知道在那些任意地址是否有任何进程被允许解决的内存(分词中断的可能性),以及,如果存在任何可访问的内存,其内容“被视为int ”可能是什么是。

编辑 :@caf指出ptr - 1无效 – 它正确指向a的最后一个元素; 所以输出(除非有一个分段错误,@ NullUserException认为这是不太可能的,但在这一点上我们不同意;-)将在第三个“任意”垃圾之前以20 50开始。 根据C标准,点有效的计算(尽管不使用)指针“只是一个结束”的数组, 并且数组的大小必须完全是该数组的长度时间其元素的大小(填充)如果需要,允许元素的类型,如果需要,它将显示在元素自己的sizeof中,但不是整个数组中的元素。 微妙但重要的;-)。

由于a的类型是5-array的数组 ,这意味着&a的类型是指向5-array的数组

当您从指针添加或减去1时,您要求它指向内存中该类型的下一个或上一个对象。 所以&a+1正在内存(不存在)之后立即创建一个指向5-数组的指针,而&a-1正在创建一个指向5-数组的指针。在记忆中(也不存在)。 在内存中,它看起来像这样(每个单元格代表一个int ):

 Address: &a-1 &a &a+1 Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? | 

当在表达式*(a+1) ,它将转换为指向其第一个元素的指针 – 因此指向10值的指针指向int 。 添加一个然后使指针指向下一个inta+1点在20值。 *(a+1)然后获取该值,因此打印的第一个数字是20。

由于ptr也是指向int的指针,这意味着ptr - 1ptr之前创建一个指向int的指针 – 在这种情况下,它将指向50.因此打印的第二个数字是50。

类似地, t + 1t之后立即创建一个指向int的指针 – 在这种情况下,它是第二个? 在上图中。 这是一个未初始化的值 – 它可以打印任何内容,甚至可以使程序崩溃。

 Address: &a-1 &a &a+1 t t+1 a a+1 ptr-1 ptr Contents: | ? | ? | ? | ? | ? | 10 | 20 | 30 | 40 | 50 | ? | ? | ? | ? | ? | 

“应该是什么结果”?

下次你想知道像这样的小代码片段应该做什么,请查看: http : //ideone.com/4fCud

我得出的结果是:

20 50 134520820

编辑:

当你运行一个程序时,看到这样的输出,然后发现自己在问“ 这个值来自哪里?” 您可能遇到了未定义的行为。

在这种情况下,第三个值并不指向您可能认为指向的位置。 它正在读取未初始化的内存(最有可能),由进程空间中的代码拥有的内存,但是在程序之外(您加载的库或C运行时),或者与该程序无关的内存(更少)可能,因为受保护的内存)。

让我们一块一块地看一下。

&a表示&a的地址。 因此,它获取整数10的地址。
&a+1是下一个指针。 所以它是存储在变量a之后的东西。 馊主意。
&a-1是存储在内存之前的东西。 再次,糟糕的主意。

*(a+1)是a指向的位置加上一个整数。 那将是a[1]或20。
*(ptr-1)a ,因为ptr&a+1 ,所以ptr-1&a 。 它是a的指针值。 将其打印为%d是一个错误。 如果你说**(ptr-1) ,你会从printf得到一个更有意义的10
*(t+1)也是a ,如上所述,但切换了优缺点。