今天我读了一个让我感到困惑的C片段:
#include <stdio.h>
int
main(void)
{
int a[] = {0, 1, 2, 3};
printf("%d\n", *(*(&a + 1) - 1));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在我看来,&a + 1毫无意义,但它运行没有错误.
有人可以解释一下这意味着什么,谢谢.K&R C圣经是否涵盖了这一点?
UPDATE0:读完答案后,我意识到这两个表达式主要让我困惑:
&a + 1,在SO中被问到:关于c中的表达"&anArray"
*(&a + 1) -1,这与阵列衰减有关.
Som*_*ude 36
首先是一个小提醒(如果之前你不知道这个,那就是新的东西):对于任何数组或指针p和索引i,表达式p[i]都与之完全相同*(p + i).
现在希望能帮助您了解正在发生的事情......
a程序中的数组存储在内存中的某个位置,这实际上并不重要.为了得到这里的位置a存储,即获得一个指针a,你用地址的操作&类似&a.这里要学习的重要一点是,指针本身并不意味着什么特别,重要的是指针的基本类型.ais 的类型int[4],即a四个int元素的数组.表达式的类型&a是指向四个数组的指针int,或int (*)[4].括号很重要,因为类型int *[4]是四个指针的数组int,这是完全不同的事情.
现在回到初始点,p[i]就是这样*(p + i).而不是p我们&a,所以我们的表达*(&a + 1)是相同的(&a)[1].
现在,这解释*(&a + 1)了它的意义和作用.现在让我们考虑一下数组的内存布局a.在内存中它看起来像
+---+---+---+---+ | 0 | 1 | 2 | 3 | +---+---+---+---+ ^ | &a
该表达式(&a)[1]视为&a一个数组数组,它肯定不是,并访问此数组中的第二个元素,这将超出范围.这当然在技术上是未定义的行为.让我们暂时运行它,并考虑它在内存中的样子:
+---+---+---+---+---+---+---+---+ | 0 | 1 | 2 | 3 | . | . | . | . | +---+---+---+---+---+---+---+---+ ^ ^ | | (&a)[0] (&a)[1]
现在请记住,类型a((&a)[0]与(&a)[1]此类型相同,因此也必须是此类型)是四个数组int.由于数组自然地衰减到指向其第一个元素的指针,因此表达式与其(&a)[1]相同&(&a)[1][0],并且其类型是指针int.因此,当我们(&a)[1]在表达式中使用时,编译器给出的是指向第二个(不存在的)数组中第一个元素的指针&a.我们再一次得到p[i]等于*(p + i)等式:(&a)[1]是一个指针int,它p在*(p + i)表达式中,所以完整的表达式是*((&a)[1] - 1),并且查看上面的内存布局int从给定的指针中减去一个(&a)[1]给出了前面的元素(&a)[1]是最后一个元素in (&a)[0],即它给了我们与之(&a)[0][3]相同的a[3].
所以表达式*(*(&a + 1) - 1)是一样的a[3].
它是啰嗦,并且经过危险的领域(越界索引),但由于指针算术的力量,它最终都有效.我不建议您编写这样的代码,但是需要人们真正了解这些转换如何能够解密它.
Ian*_*ott 13
让我们剖析它.
a有类型int [4](数组为4 int).它的大小是4 * sizeof(int).
&a有类型int (*)[4](指向4 int数组的指针).
(&a + 1)也有类型int (*)[4].它指向一个4 int的数组,它在开始之后开始1 * sizeof(a)字节(或4 * sizeof(int)字节)a.
*(&a + 1)是类型int [4](4 int的数组).它的存储开始是1 * sizeof(a)字节(或4 * sizeof(int)开始后的字节)a.
*(&a + 1) - 1是类型int *(指向int的指针),因为数组*(&a + 1)衰减到指向此表达式中第一个元素的指针.它将指向一个在开始1 * sizeof(int)之前开始字节的int *(&a + 1).这与指针值相同&a[3].
*(*(&a + 1) - 1)是类型的int.因为*(&a + 1) - 1是相同的指针值&a[3],*(*(&a + 1) - 1)相当于a[3]已经初始化为3,所以这是由打印的数字printf.
&a + 1将指向紧跟在最后一个a元素之后的内存或更好地说在a数组之后,因为它&a具有类型int (*)[4](指向四个数组的指针int).标准允许构造此类指针,但不允许解除引用.因此,您可以将其用于后续的算术.
所以,结果*(&a + 1)是未定义的.但是*(*(&a + 1) - 1)更有趣的是.实际上它被评估为最后一个元素.a有关详细说明,请参阅/sf/answers/2674172861/.只是一个评论 - 这个hack可能会被更可读和更明显的构造所取代:( a[sizeof a / sizeof a[0] - 1]当然它应该仅应用于数组,而不应用于指针).