我们有
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));
结果应该是什么?
答案 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));
后跟两个完全任意的整数值。由于20
和ptr
是指向t
的指针,因此int
和-1
的地址算术缩放确实不补偿完成在+1
上(内存地址的缩放是&a
,而不是sizeof(int)
!),因此sizeof(a)
和ptr-1
指向(涉嫌; - )t+1
分别是“int
”结束后的几个int
和a
开始前的几个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
,如上所述,但是切换了优缺点。