关于for循环的谜团

Pri*_*han 2 c for-loop

我对这个关于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的输出.


mpe*_*kov 5

您正在索引超过数组的末尾(缓冲区溢出)并重新分配堆栈上的其他变量.

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哪个只是"死空间".