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

C 当变量未初始化时,为什么此程序会产生奇数输出?,c,loops,scope,shadowing,C,Loops,Scope,Shadowing,我无法理解为什么迭代2,3,4,5中的第二个printf值 是五岁 我对每次迭代中第一个值为什么为0的理解是i在for循环中的范围是局部的,当i在for循环中声明时,它会在我们进入新迭代时立即被销毁 但是我无法理解为什么这个值在第二次printf时变为5。程序的行为是未定义的 内部作用域i未在读取点初始化 (可能发生的情况是,在后续迭代中重新引入的i与内部i的前一个版本占用相同的内存,并且在第一次迭代中未初始化的内存对应于0。但是不依赖于此。在其他情况下,编译器可能会吃掉您的猫。)如果您声明了一

我无法理解为什么迭代2,3,4,5中的第二个
printf
值 是五岁

我对每次迭代中第一个值为什么为0的理解是
i
for
循环中的范围是局部的,当
i
for
循环中声明时,它会在我们进入新迭代时立即被销毁


但是我无法理解为什么这个值在第二次
printf

时变为5。程序的行为是未定义的

内部作用域
i
未在读取点初始化


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

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

C标准说

具有自动存储持续时间的变量每次都会初始化 执行其声明语句的时间。具有自动控制功能的变量 块中声明的存储持续时间将在退出时销毁 街区


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

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


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

我认为这就是正在发生的情况:

Iteration 1 :  0 0
Iteration 2 :  0 5
Iteration 3 :  0 5
Iteration 4 :  0 5
Iteration 5 :  0 5
abc.c:4处的断点1,main() 4 int j=0; (gdb)s 5 int i=0; (gdb)
6 for(j=0;jC编译器在如何实现方面有一定的自由度,对于本地“i”来说,这一点也不奇怪不会在循环的每个过程中实际重新创建。它实际上可能只创建一次,并在每个过程中重复使用。在这种情况下,您的第一次打印不在局部变量的范围内,因此使用循环外部的i。第二次打印使用局部i,因为它在范围内,并且在第一次迭代设置为5之后。在在第一次迭代中,正确的值是未定义的,而不是0,但未定义的行为是特定于实现的,在您的实现中,它似乎自动初始化为0。

问得好,可惜答案太简单了。@Bathsheba-您总是可以有意地将答案变得冗长:p注意:这称为“隐藏”强烈建议不要使用它,因为它没有任何好处,buit非常容易出错。启用所有建议的编译器警告,其中一个应该警告此类有问题的定义。您是对的,它在每次迭代中都超出了范围,但通常下一次迭代将使用与上一次相同的内存,原因是为什么不,给出了ap在添加到的注释时出现初始化,对于GCC
-Wshadow
。不,
int
可以包含陷阱表示。如果它是
无符号字符
,则您将是正确的。@Bathsheba它甚至都不正确。它没有地址,因此具有未定义的行为。如果它确实有地址,它将具有不确定的值(即使是无符号字符)在库函数中使用它会有未定义的行为。它总是UB,根据。击败死马,我已经链接了一个答案,说明了为什么它总是UB。陷阱表示与否并不重要。正如Antti所说,这是因为它是一个自动变量,没有地址。C116.3.2.1。“在其他情况下,编译器可能会吃掉你的猫。“哦,别这样!别再胡说八道了,编译器!就在最后一个小时,你已经吃掉了我的50只猫。难怪这么多年来,你吃了这么多猫,你的安装规模就这么大了。我不明白这一段有什么关系……它真的没有提到UB。这个答案不正确,引用的部分也不相关。”。
Iteration 1 :  0 0
Iteration 2 :  0 5
Iteration 3 :  0 5
Iteration 4 :  0 5
Iteration 5 :  0 5
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)