C 中未初始化变量的行为

问题描述

我有一个关于未初始化变量如何在 C 中工作的问题。如果我声明一个变量然后打印它,程序应该打印一个随机值,但是我的程序几乎总是输出 0。如果我尝试声明第二个变量,程序总是输出 16 作为新分配的值。

#include <stdio.h>
int main(){
int x,y,z,t;
printf("%d  %d",x,y);
}

该程序输出 0 和 16,但是如果我添加以下代码行:y--; 在声明变量之后但在打印它们之前,程序输出 x=15 和 y =-1,完全不同的值从我之前所拥有的。为什么会发生这种情况? C 如何处理未初始化的变量?

解决方法

根据标准(草案 N1570),以下内容适用:

6.2.4

对象的初始值是不确定的。

这在

中进一步描述

6.7.9

如果没有显式初始化具有自动存储期的对象,则其值为 不确定。

“不确定”的定义说

3.19.2

不确定值

未指定的值或陷阱表示

最后

J.2 未定义行为

在以下情况下行为未定义:

...

具有自动存储期的对象的值被使用时 不确定 (6.2.4,6.7.9,6.8).

综上所述:在读取未初始化的变量时无法知道您得到了什么值,而且甚至不确定您的程序是否会继续执行,因为它可能是一个陷阱。

,

回答这个问题的一种方法是,当你读到“未初始化的变量开始包含随机值”时,在这种情况下,你看到的那些值 0、16、15 和 -1 “随机”。

现在,这是真的,它们肯定不是随机的,比如掷骰子是随机的。它们似乎保持不变,然后无缘无故地更改,例如更改程序的其他部分时。

但你显然无法预测它们。所以你显然不能使用它们,或者以任何方式依赖它们。它们也可能是真正随机的。

为什么他们有自己的价值观?这几乎是不可能的。不管是什么原因,它们往往不是很有趣。无论原因是什么,了解它们并不重要,因为您永远不会依赖于这些价值观。

这有点像问,“我把厨房桌子上的四只脚都锯掉了。所有东西都掉在地上摔碎了。除了一个盘子没有碎。为什么它没有碎?还有一个苹果,还有它滚进客厅。我还以为它会滚下地下室的楼梯。它为什么滚进客厅?”

您问题的另一部分与您未初始化的变量 y 似乎开始包含值 16 的事实有关,但是当您添加语句 y-- 时,该值变为 - 1.这是怎么回事?

答案是我们谈论的是初始化的变量和可预测的行为。当您未能初始化变量时,这意味着您的程序具有不可预测的行为,不会 发生的是某处的某个 oracle 为您的变量选择一个初始值,然后安排有关您的程序的所有其他内容可预测。不,您的程序不可预测意味着您无法预测它!如果这个不可预测的值昨天看起来是 16,你就无法预测明天减去 1 会得到 15。

(继续我愚蠢的比喻,如果你明天再次看到厨房桌子上的腿,你不会期望你最终会再次得到一个完整的盘子。如果你把腿锯掉在一个不同的顺序,希望桌子以不同的角度落下,并像您预期的那样将苹果引导下地下室楼梯,如果它不起作用,您可能不会失望。)

如果您真的想知道发生了什么,部分答案是局部变量通常存储在 the stack 上,并且它们开始时包含堆栈中该位置剩余的任何“随机”位模式由上次使用该堆栈的任何函数作为其自己的变量。因此,任何在堆栈上移动事物,导致未初始化变量在堆栈帧中占据不同位置,或者导致前一个函数在堆栈上留下不同垃圾的任何事情,都将导致未初始化变量开始持有不同的“随机”值。有关尝试使用未初始化的基于堆栈的变量时会发生什么的更多讨论,请参阅 this other answer

另见xkcd 221