我对这个关于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]的值时发生。
也许我错过了一些非常明显的东西。任何帮助将不胜感激。
答案 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循环结束时有一个分号。问题解决了。