没有躲过的坑--程序中的变量未初始化

标签: c++初始化
11251人阅读 评论(2) 收藏 举报
分类:

变量未初始化是C++编程中最为常见和易犯的错误之一。

但是对于全局变量,我们可以不进行初始化,这个变量会默认的用零进行初始化,但是这通常不是一个好的习惯。我们今天先不探讨全局变量还是静态全局变量。那么对于一个全部变量来说,初始化为零和不初始化(编译器替我们初始化为零)又有什么区别吗?

全局变量和局部变量初始化与不初始化的区别
即int x 和 int x=0的区别。

int x =0; 跟 int x; 的效果看起来是一样的。但其实这里面的差别很大,强烈建议大家所有的全局变量都要初始化,他们的主要差别如下:

编译器在编译的时候针对这两种情况会产生两种符号放在目标文件的符号表中,对于初始化的,叫强符号,未初始化的,叫弱符号。连接器在连接目标文件的时候,如果遇到两个重名符号,会有以下处理规
则:
1、如果有多个重名的强符号,则报错。
2、如果有一个强符号,多个弱符号,则以强符号为准。
3、如果没有强符号,但有多个重名的弱符号,则任选一个弱符号。

例:

#include "stdafx.h"
int i;
int main(int argc, char* argv[])
{
 printf(" i = %d\n",i);
 int j;
 printf(" j= %d\n",j);
 return 0;
}

在Debug版下,i输出是0,j输出是-858993460,也就是0xCCCCCCCC。
至于为什么是这个值,有网友给出这个解释。(设计成0xcccccccc是有特殊用意的……这个好像叫做Poison,未初始化的Pointer去取值的话会出错。肯定有人问为什么不弄成0x00000000,因为空指针是指针的有效状态,可能会误导人,而0xCCCCCCCC在Windows下永远不可能是一个指针的有效状态(不是NULL,不指向一个对象,不指向一堆对象紧接之后的区域),这就是在模拟野指针……)

值得注意的是,同样的代码在Release版下,这段代码中未被初始化的变量最后打印出来的可能都是0。也有强大的网友给出解释。(重点在于vc的一个功能:Catch release-build errors in debug build用/GZ编译开关打开。debug版这个开关是开的,release版是关的(为了效率)。这个开关说白了就是把所有动态局部变量初始化成0xcccccccc,把所有动态堆变量初始化成0xcdcdcdcd。很多新手会忘记初始化这些本来应该初始化的变量(尤其是new出来的变量),有时他们会假定这些变量应该是0,这样就可能出现在release版正常而debug版不正常的程序,因为release版至少局部变量的初始值很可能就是0,而有时他们又会假定或者期望这些变量不是0,这样就带了一个最难发现的bug)

上面的内容出自:
http://www.kingofcoders.com/viewNews.php?type=newsCpp&id=189&number=4836955386

================================================

在C++中,为变量所分配的内存空间并不是完全“干净的”,也不会在分配空间时自动做清零处理。其结果就是,一个未初始化的变量将包含某个值,但没办法准确地知道这个值是多少。此外,每次执行这个程序的时候,该变量的值可能都会发生改变。这就有可能产生间歇性发作的问题,是特别难以追踪的。看看如下的代码片段:

if (num_value)
{}
else
{}

如果num_value是未经初始化的变量,那么if语句的判断结果就无法确定,两个分支都可能会执行。在一般情况下,编译器会对未初始化的变量给予提示。下面的代码片段在大多数编译器上都会引发一个警告信息。

int foo()
{
    int number;
    return number;
}

但是,还有一些简单的例子则不会产生警告:

void increment(int &num_value)
{
    ++num_value;
}
int foo()
{
    int number;
    increment(number);
    return number;
}

以上的代码片段可能不会产生一个警告,因为编译器一般不会去跟踪查看函数increment()到底有没有对nValue赋值。

未初始化变量更常出现于类中,成员的初始化一般是通过构造函数的实现来完成的。

class Foo
{
private:
    int num_value_;
public:
    Foo();
    int GetValue() { return num_value_; }
};

Foo::Foo()
{

// Oops, 我们忘记初始化num_value_了
}

int main()
{
    Foo cFoo;
    if (cFoo.GetValue() > 0)

// do something
    else

// do something else
}

注意,num_value_从未初始化过。结果就是,GetValue()返回的是一个垃圾值,if语句的两个分支都有可能会执行。

==================================================
新手程序员通常在定义多个变量时会犯下面这种错误:

int nValue1, nValue2 = 5;

这里的本意是nValue1和nValue2都被初始化为5,但实际上只有nValue2被初始化了,nValue1从未被初始化过。

切记 无论什么变量,记得初始化!!!!

2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:4200091次
    • 积分:38640
    • 等级:
    • 排名:第113名
    • 原创:554篇
    • 转载:28篇
    • 译文:13篇
    • 评论:742条
    微信公众号
      我的微信公众号
      为你推荐最新的博文~更有惊喜等着你
    时光荏苒
      白驹过隙
    博客专栏
    文章分类
    百度统计
    Google Analytics