当我遇到这个时,我正准备即将开始的考试:
char a = 'a'; char b = 'b'; int ai[] = { 1, 2 }; int i = 0;
假设字长为32位,int为32位,并且内存分配的顺序与从地址68开始的声明相反。
绘制一个图表,显示执行以下代码行的效果。
for (i = 0; i < 8; i++) *(&a – i) = 'z';
这可能听起来很奇怪,但我是C的新手,这是我第一次见到for循环的乘法。这个for循环的解释和应用它的乘法将是值得赞赏的。
答案 0 :(得分:3)
这不是乘法,而是取消引用指针。但是,*(&a – i)
在i > 0
时已经是未定义的行为。然而,在您的特定问题中,有独角兽和UB是过去的事情,并且您必须假设变量分配以相反的顺序完成它们被声明,并且没有任何填充,这将覆盖变量{{ 1}}和b
。
答案 1 :(得分:3)
我认为我们可以假设这是一个理论问题,如果在问题中没有定义的额外假设(即字节顺序,填充) - 问题是可以回答的。但是,正如@chux指出的那样,有针对此类行为的标准。因为,如果允许,代码会导致堆栈内存损坏。作为一个考试问题,它实际上是要求你绘制哪个内存被破坏的图表。
如果我正确地解释了这个问题,那么一个可能的存储器表示(假设整数是LSB,有1个字节填充,并且声明的顺序相反):
| Addr | Value | Desc |
| ---- | ----- | ------------------------------ |
| 55 | 0x00 | // int i = 0; |
| 56 | 0x00 | |
| 57 | 0x00 | |
| 58 | 0x00 | |
| 59 | 0x01 | // int ai[] = { 1, 2 }; |
| 60 | 0x00 | |
| 61 | 0x00 | |
| 62 | 0x00 | |
| 63 | 0x02 | |
| 64 | 0x00 | |
| 65 | 0x00 | |
| 66 | 0x00 | |
| 67 | 0x62 | // char b = 'b'; |
| 68 | 0x61 | // char a = 'a'; |
展开的循环评估为:
[68] = 0x7a; // 'z';
[67] = 0x7a; // 'z';
[66] = 0x7a; // 'z';
[65] = 0x7a; // 'z';
[64] = 0x7a; // 'z';
[63] = 0x7a; // 'z';
[62] = 0x7a; // 'z';
[61] = 0x7a; // 'z';
所以记忆由变量表示,a,b和ai []数组的部分将被破坏。 (纳入@chux关于endianess的观察。另外,我根据@chux和@Peter A调整了ai []元素出现的顺序.Schneider评论。)
| Addr | Value | Desc |
| ---- | ----- | ----------------------------------------- |
| 55 | 0x08 | // int i = 8; |
| 56 | 0x00 | |
| 57 | 0x00 | |
| 58 | 0x00 | |
| 59 | 0x01 | // int ai[] = { 0x7a7a0001, 0x7a7a7a7a }; |
| 60 | 0x00 | |
| 61 | 0x7a | |
| 62 | 0x7a | |
| 63 | 0x7a | |
| 64 | 0x7a | |
| 65 | 0x7a | |
| 66 | 0x7a | |
| 67 | 0x7a | // char b = 'z'; |
| 68 | 0x7a | // char a = 'z'; |