关于for循环的谜团

时间:2011-02-01 07:01:57

标签: 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 

输出应该是3,3,因为我没有改变j的值。

在abc的第j个值上加3会导致j的值变为3.这只在从for循环退出然后尝试更改abc [j]的值时发生。

也许我错过了一些非常明显的东西。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:15)

你有一个缓冲区溢出,因为你声明你的数组大小为3 int abc[3];但你正在索引第4个元素;这是未定义的行为

abc[j] = abc[j] + 3; // j = 3 here, overflow

您最有可能看到的是j位于数组abc之后的堆栈中,所以当您使用abc[3]溢出数组时,实际上是修改包含j的内存。

*请注意,在C标准中没有提到 stack 这个词,这是一个实现细节,可以在系统之间进行更改。这部分是为什么它是未定义的行为的原因,你得到了人们的反应,他们认为两个3是输出。

答案 1 :(得分: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);

要验证,请尝试在最后添加以下语句:

printf("%d\n", &i == &abc[3]);
printf("%d\n", &j == &abc[3]);

修改

根据您正在使用的编译器,堆栈的确切布局将很重要:

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

这就是为什么它在我的机器上工作正常 - 声明:

printf("abc: %x abc[3]: %x i: %x j: %x\n", &abc, &abc[3], &i, &j);

给出以下输出:

abc: 4cd0aa70 abc[3]: 4cd0aa7c i: 4cd0aa8c j: 4cd0aa88

所以堆栈实际上是:

//  aa70   aa74     aa78   aa7c            aa88  aa8c
// |abc[0]|abc[1]| abc[2]|      |  ....  |  j  |  i  |

因此,当它访问abc[3]时,它正在访问0x4cd0aa7c,这只是“死空间”。

答案 2 :(得分:1)

当J = 3时,abc [j]指的是第4个元素,因为,数组索引从0开始而不是1.因此,您试图访问超出数组abc的内存区域的位置。巧合的是,这个位置恰好是J的位置。因此,J的值会被修改。尝试更改变量声明的顺序,以便更好地理解这种行为。

谢谢,
Vamyip

答案 3 :(得分:0)

for(j = 0; j <3; j ++);

在for循环结束时有一个分号。问题解决了。