指针和数组混淆

时间:2010-08-09 04:31:26

标签: c

我们有

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

结果应该是什么?

4 个答案:

答案 0 :(得分:6)

由于a的类型是 array-of-5 - int s ,这意味着&a的类型是指针 - 到阵列-的-5 - intŠ

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

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

在表达式a中使用*(a+1)时,它会转换为指向其第一个元素的指针 - 所以指向int的指针指向10值。向其中添加一个然后使指针指向int值处的下一个a+1 - 20点。 *(a+1)然后提取该值,因此打印的第一个数字是20。

由于ptr也是指向int的指针,这意味着ptr - 1会在int之前创建指向ptr的指针 - 在此例如,它将指向50.所以打印的第二个数字是50。

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

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

答案 1 :(得分:4)

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

所以,在

之后
int

int *ptr = (int *)(&a+1); int *t = (int *)(&a -1); 是指向内存地址“sizeof(a)多于地址a”的int的指针,ptr类似于“sizeof(a)小于a的地址”。因此...

t
  

结果应该是什么?

很可能是分段违规,否则 printf("%d %d %d \n", *(a+1), *(ptr-1), *(t+1)); 后跟两个完全任意的整数值。由于20ptr是指向t的指针,因此int-1的地址算术缩放确实补偿完成在+1上(内存地址的缩放是&a,而不是sizeof(int)!),因此sizeof(a)ptr-1指向(涉嫌; - )t+1分别是“int”结束后的几个inta开始前的几个int

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

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

答案 2 :(得分:0)

“应该是什么结果”?

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

我得出的结果是:

  

20 50 134520820

修改

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

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

答案 3 :(得分:-1)

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

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

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