在声明变量的时候,有的人不会对变量进行初始化,要不就是为了少输入几个字符,要不就是忘记了,可能就埋下了隐患。
1、野指针
int *ptr; //野指针
*ptr = 10; //修改野指针指向内存区域,有可能出现问题
上面的代码,在声明ptr的时候没有对其进行赋NULL,当尝试修改野指针指向的内存区域,运气好的时候,赋值操作不会出现问题;运气不好的时候,就会写乱了内存,或者导致程序崩溃。
int *ptr = new int(10);
delete ptr; //ptr所指内存被释放,但ptr指向的内存地址没变,ptr变为野指针
if (NULL != ptr)
{
*ptr = 8; //修改野指针ptr指向的内存区域,有可能出现问题
}
上面的代码,当ptr被delete后,并没有对其赋NULL,当尝试修改野指针指向的内存区域,有可能出现上例的问题。
int *ptr = new int(10);
delete ptr; //释放ptr所指内存
...
//某些逻辑
...
delete ptr; //两次释放ptr所指内存,出现coredump,程序崩溃
上面的代码,当ptr第一次被delete后,并没有对其赋NULL,当程序逻辑复杂的时候,程序员可能忘记了前面已经delete过了,就有可能对ptr进行第二次delete,此时就会出现coredump。如果在第一次delete之后马上给ptr赋NULL,第一次delete操作就没有问题了,因为允许对指向NULL的指针进行多次delete操作。
指针用得好会给程序员带来非常的便利,用得不好,则会给程序员带来无尽的痛苦,对于野指针问题,要记住两点:
1) 声明一个指针的时候注意初始化为NULL
int *ptr = NULL;
2) 释放之后怎指向内存区域后,记得赋NULL
delete ptr;
ptr = NULL;
2、栈垃圾数据
void Func()
{
int bar;
printf("%d\n", bar);
bar = 2;
}
int main()
{
Func(); //输出:0
Func(); //输出:2,此处输出的是垃圾数据
}
上面main函数中,第一次调用Func函数时,输出为0,因为编译器给变量bar赋了一个默认值0(注意,不同的编译器的实现不一样);第二次调用Func函数时,输出为2,是一个垃圾数据,这是为什么呢?
以gcc为例,编译器对于函数的处理是,先将当前函数后的下一条要执行的语句压栈,然后将函数返回值压栈,接着对实参从左到右求值,从右到左压栈,最后就对函数局部变量进行压栈。上面main函数中的执行流程大概如下:
1) 第一个Func函数执行时,先将第二个Func函数调用语句压栈;
2) 将Func函数的返回值压栈;
3) 由于没有实参,第一个Func函数的局部变量bar将会被压栈;
4) 由于bar没有初始化,编译器给其赋默认值0;
5) 打印bar之后,对栈中的bar变量赋值为2;
6) 将bar出栈;
7) 将返回值出栈;
8) 将第二个Func函数调用出栈;
对于第二个Func函数的执行流程与第一个Func函数的执行流程一样,但是要注意一点是,所谓的出栈,其实只是标记对应的栈位置可以再用,并没有对里面的数据重新初始化,而第二个Func函数的局部变量bar刚好进栈位置是第一个Func函数的局部变量bar所处的位置,此时第二个bar变量的值就继承了第一个bar变量的值2,因此出现了上面main函数的输出为0和2,很明显第二个bar变量的数据是脏数据。
如何避免这个问题呢?还是那句,初始化吧,少年,打多几个字符,幸福千万家啊,不然出现这些奇葩问题,就苦了后面来的一大堆苦b程序员啊!