我对这个关于for循环的谜团感到困惑.
int abc[3], i, j;
for(j=0; j<3; j++);
printf("%d\n", j);
abc[j] = abc[j] + 3;
printf("%d \n", j);
Output:
3
6
Run Code Online (Sandbox Code Playgroud)
输出应该是3,3,因为我没有改变j的值.
向abc的第j个值添加3导致j的值变为3.这仅在从for循环退出然后尝试更改abc [j]的值时发生.
也许我错过了一些非常明显的东西.任何帮助将非常感激.
Sie*_*geX 15
你有一个缓冲区溢出,因为你声明你的数组大小为3,int abc[3];但你正在索引第4个元素; 这是未定义的行为.
abc[j] = abc[j] + 3; // j = 3 here, overflow
Run Code Online (Sandbox Code Playgroud)
您最有可能看到的j是位于堆栈上的数据abc,因此当您通过数组溢出一个时abc[3],您实际上正在修改包含的内存j.
*请注意,在C标准中没有提到单词堆栈,这是一个实现细节,可以在系统之间进行更改.这部分是为什么它是未定义行为的原因,你得到人们的反应,他们看到两个3的输出.
您正在索引超过数组的末尾(缓冲区溢出)并重新分配堆栈上的其他变量.
int abc[3], i, j;
// Your stack looks like this (single 'x' is one byte):
// |abc[0]|abc[1]| abc[2]| j | i |
//
// |xxxx |xxxx |xxxx |xxxx|xxxx|
//
for(j=0; j<3; j++);
printf("%d\n", j);
// j = 3 at this point
// abc[3] points past the end of the array abc, in this case, at j.
// So the next statement increments j by 3.
abc[j] = abc[j] + 3;
printf("%d \n", j);
Run Code Online (Sandbox Code Playgroud)
要进行验证,请尝试在最后添加以下语句:
printf("%d\n", &i == &abc[3]);
printf("%d\n", &j == &abc[3]);
Run Code Online (Sandbox Code Playgroud)
编辑
堆栈的确切布局将取决于您使用的编译器:
misha@misha-desktop:~/Desktop/stackoverflow$ gcc --version
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
misha@misha-desktop:~/Desktop/stackoverflow$ ./a.out
3
3
Run Code Online (Sandbox Code Playgroud)
这就是为什么它在我的机器上工作正常 - 声明:
printf("abc: %x abc[3]: %x i: %x j: %x\n", &abc, &abc[3], &i, &j);
Run Code Online (Sandbox Code Playgroud)
给出以下输出:
abc: 4cd0aa70 abc[3]: 4cd0aa7c i: 4cd0aa8c j: 4cd0aa88
Run Code Online (Sandbox Code Playgroud)
所以堆栈实际上是:
// aa70 aa74 aa78 aa7c aa88 aa8c
// |abc[0]|abc[1]| abc[2]| | .... | j | i |
Run Code Online (Sandbox Code Playgroud)
因此,当它正在访问时abc[3],它正在访问0x4cd0aa7c哪个只是"死空间".