在下面的代码中,变量没有初始值并打印了这个变量。
int var;
cout << var << endl;
输出:2514932
double var;
cout << var << endl;
输出:1.23769e-307
我不明白这些输出数字。谁能给我解释一下?
在下面的代码中,变量没有初始值并打印了这个变量。
int var;
cout << var << endl;
输出:2514932
double var;
cout << var << endl;
输出:1.23769e-307
我不明白这些输出数字。谁能给我解释一下?
简而言之,var
未初始化,读取未初始化的变量会导致未定义的行为。
所以不要这样做。在你这样做的那一刻,你的程序不再保证做你所说的任何事情。
形式上,“读取”一个值意味着对其执行左值到右值的转换。§4.1 指出“...如果对象未初始化,则需要进行此转换的程序具有未定义的行为。”
务实地说,这只是意味着该值是垃圾(毕竟,很容易看到读取int
,例如,只是获取随机位),但我们无法得出结论,否则您将定义未定义的行为。
举一个真实的例子,考虑:
#include <iostream>
const char* test()
{
bool b; // uninitialized
switch (b) // undefined behavior!
{
case false:
return "false"; // garbage was zero (zero is false)
case true:
return "true"; // garbage was non-zero (non-zero is true)
default:
return "impossible"; // options are exhausted, this must be impossible...
}
}
int main()
{
std::cout << test() << std::endl;
}
天真地,人们会得出结论(通过评论中的推理)这不应该打印"impossible"
;但是对于未定义的行为,一切皆有可能。用 编译它g++ -02
。
当你这样做时:
int var;
您只是在声明一个名为 的整数var
。您不使用值对其进行初始化,因此无论在什么位置var
,都将是垃圾数据。
int var = 5;
将声明 var 并将其初始化为 5。
你得到的是任何数据在编译器决定变量应该解释为整数或双精度的地方发生在堆栈上。每次您的程序运行时,它可能都是相同的,因为程序通常具有确定性。尽管在许多情况下,程序的每次运行最终都会不一样。如果您稍微更改您的程序,或者让它在您获得该代码之前根据用户输入做出决定,您可能会或可能不会获得不同的数字。
基本上,您尚未初始化的变量的值是未指定的,并且可能绝对是任何值。那里的东西没有押韵或理由。使用未初始化的变量(正式而言)是未定义的行为,可能会导致各种奇怪的事情。
这样做通常是不好的做法。您希望程序以可预测的方式运行,并且具有未初始化的变量是不可预测的根源。请注意,它最强调不是随机性的来源,只是不可预测性。如果您打开所有警告,大多数编译器都会抱怨这样的代码。
在 C++ 中,当您声明一个变量时,编译器会为其分配一个内存地址。就是这样,没有进行任何清理。这主要是因为 C++(和 C)在构建时考虑到了性能。C++ 不会花时间初始化地址,除非你明确告诉它这样做。
你看到的所谓垃圾就是最后一个使用它的变量留在那个地址的任何东西。
其他语言将为您初始化数据。事实上,C# 在初始化之前不会让您使用该变量。这些语言被设计为安全的,从某种意义上说,它不会让您编写错误地使用未初始化地址的代码并使您的程序崩溃,或者更糟的是,破坏您的数据。
在这两种情况下你都没有初始化var
,所以你得到了垃圾输出。
你做完了吗
const int var(5);
它将被初始化为值5
当您声明var时,它会在内存中分配一个位置。但是,默认情况下该内存未设置为任何内容,因此您可以选择之前的任何内容。这将是一些没有意义的垃圾值。
在 C++ 中,成员变量和局部变量都是如此。但是,在 Java 和 C# 等语言中,对于数字类型,您的成员变量会自动初始化为 0,对于布尔值,您的成员变量会自动初始化为 false,对于引用,您的成员变量会自动初始化为 null。这不适用于局部变量,并且(至少在 C# 编译器中)如果您尝试获取未初始化变量的值,您的构建将失败。