当变量未初始化时,为什么这个程序会产生奇数输出?

时间:2017-02-23 15:26:33

标签: c loops scope shadowing

int main() {
    int j = 0;
    int i = 0;
    for (j = 0; j < 5; j++) {
        printf("Iteration %d :  %d ", j + 1, i);
        int i;
        printf("%d", i);
        i = 5;
        printf("\n");
    }
}

以上代码生成以下输出:

Iteration 1 :  0 0
Iteration 2 :  0 5
Iteration 3 :  0 5
Iteration 4 :  0 5
Iteration 5 :  0 5

我无法理解迭代2,3,4,5中第二个printf值的原因 是5。

我理解每次迭代中第一个值为0的原因是i循环中for的范围是本地的,一旦我们进入新的迭代,它就会被销毁{在i循环中声明了{1}}。

但是我无法弄清楚为什么这个值在第二个for变为5。

5 个答案:

答案 0 :(得分:53)

程序的行为是未定义

内部范围i在读取时不会初始化

可能正在发生的事情是,在后续迭代中重新引入的i占用与内部i的前一个版本相同的内存,以及未初始化的内存第一次迭代对应于0.但依赖于此。在其他情况下,编译器可能会吃掉你的猫。)

答案 1 :(得分:9)

程序中的第二个printf是从未初始化的局部变量i打印垃圾值。一般情况下,行为未定义。

意外地,代表您的i(存储器单元或CPU寄存器)的存储位置在周期的每次迭代中都是相同的。另一个意外,循环的主体作为每次迭代的单个复合语句执行(而不是展开循环并以交错方式同时执行所有迭代)。另一次事故中,i的存储位置保留了之前迭代的旧值。因此,您正在打印的垃圾与循环的上一次迭代中该位置的最后存储值匹配。

这就是为什么除了第一次迭代之外,每次迭代都会在本地5中看到i的原因。在第一次迭代中,垃圾值恰好是0

答案 2 :(得分:6)

我认为这就是发生的事情:

Breakpoint 1, main () at abc.c:4
4       int j = 0;
(gdb) s
5       int i = 0;
(gdb)
6       for(j=0;j<5;j++){
(gdb) p &i
$23 = (int *) 0x7fff5fbffc04           //(1) (addr = 0x7fff5fbffc04) i = 0
(gdb) p i
$24 = 0                                              // (2) i == 0
(gdb) s
7           printf("Iteration %d :  %d ",j+1,i);
(gdb) p &i
$25 = (int *) 0x7fff5fbffc00            //(3) here compiler finds there is contention in variable 'i' and assigns the inner one which is in present scope. Now, when subroutines are called, the stack frame is populated with (arguments, return address and local variables) and this is when the inner 'i' was also got allocated in this inner loop block but not initialized yet and this is the reason i get garbage value in the first integration output.

(gdb) p i
$26 = 1606417440                          // (4)  Here i == 1606417440 (Garbage)
(gdb) s
9           printf("%d",i);
(gdb) s
10          i = 5;
(gdb) p &i
$27 = (int *) 0x7fff5fbffc00
(gdb) p i
$28 = 1606417440
(gdb) s
11          printf("\n");
(gdb) p &i
$29 = (int *) 0x7fff5fbffc00
(gdb) p i                                                //(5) after executing previous statement, now i == 5
$30 = 5
(gdb) 

答案 3 :(得分:1)

C编译器在如何实现它们方面有一定的自由度,对于本地&#34; i&#34;它们并不常见。实际上并没有在循环的每次传递中重新创建。它实际上可能只创建一次,并在每次传递时重复使用。在这种情况下,您的第一个打印超出了局部变量的范围,因此使用循环外部的i。第二个打印使用本地i,因为它在范围内,并且在第一次迭代设置为5.在第一次迭代时,正确的值是未定义的,而不是0,但undefined的行为是特定于实现的,在您的实现中它似乎自动初始化为0。

答案 4 :(得分:0)

如果您声明了一个局部变量,并且在使用它之前没有给它一个值,那么如果你得到的是未定义的行为。

C标准说,

  

每个都会初始化具有自动存储持续时间的变量   他们的声明声明被执行的时间。自动变量   块中声明的存储持续时间在退出时被销毁   块。

相关问题