【问题标题】:Mystery regarding for-loop关于for循环的谜团
【发布时间】:2011-02-01 07:01:57
【问题描述】:

我被这个关于 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 的值。

将 3 加到 abc 的第 j 个值会导致 j 的值改变 3。这仅在退出 for 循环然后尝试更改 abc[j] 的值时发生。

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

【问题讨论】:

  • 我的 VC++ 编译器输出 3 3
  • 数组 abc 初始化为什么?

标签: c for-loop


【解决方案1】:

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

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

您最有可能看到的是,j 位于堆栈上,就在您的数组 abc 之后,因此当您使用 abc[3] 溢出数组时,您实际上是在修改包含 @ 的内存987654326@.

*请注意,在 C 标准中没有任何地方提到过 stack 这个词,这是一个实现细节,可能会因系统而异。这就是为什么它是未定义的行为的部分原因,并且您会收到人们的回应,他们将两个 3 视为输出。

【讨论】:

  • 谢谢。为什么 j 的值会增加,这仍然让我感到困惑。
  • @primalpop 刷新我的答案 =)
【解决方案2】:

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

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,这只是“死区”。

【讨论】:

  • 抱歉,这是我第一次匆忙编辑。我去更新的时候把它删了,但显然我不够快。
【解决方案3】:

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

谢谢,
瓦米普

【讨论】:

    【解决方案4】:

    for(j=0;j

    for 循环的末尾有一个分号。问题解决了。

    【讨论】:

    • 仔细看问题
    • for 循环语句末尾的分号始终是一个错误,无论是有意的错误还是无意的错误。如果您打算使用空循环,请将分号单独放在一行。 如果你打算使用一个空循环,声明迭代器 volatile 或者根本不保证循环会被执行。
    • 请参阅我的第一条评论,因为您刚才所说的与手头的问题无关。在这种情况下,不需要声明迭代器volatile,因为即使优化了循环,这并不意味着迭代器将具有未定义的值。在这种 OP 的情况下,编译器将简单地将常量 3 分配给迭代器。
    • @SiegeX 那你为什么要写一个循环,而不仅仅是 j=3?
    • 我猜 OP 希望对他现有的代码进行最小的更改,同时仍然提供足够的奇怪行为仍然存在。很可能他认为 for 循环是相关的,但在这种情况下并非如此。
    猜你喜欢
    • 2019-07-07
    • 2012-01-07
    • 2019-02-10
    • 2021-04-25
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多