7.1.2 野指针
前面提到指针消亡,并不意味着其指向的内存会被自动释放,同样释放动态内存,并不意味着指针会消亡,也不意味着指针的值会改变,如下所示。
int*p=new int[8]; …… delete[]p;
指行完delete[]p后,指针p是不是就自动消亡了呢?错,不论是使用delete/delete[]还是使用free(),指针p非但不会消亡,其值也保持不变,并不会变为null。这时,使用“if(p!=null)”进行处理也无法起到防错作用。
为此,指针被free或delete/delete[]后,一定要置为null,没有置为null的指针常称为“野指针”,释放掉的堆内存会被内存管理器重新分配,野指针指向的内存已经被赋予新的意义。如果使用野指针释放或再次访问这块内存,会给程序带来灾难性的后果。
此外,下列两种情况也可以称为“野指针”。
1.未初始化指针
第4章中已经提到,任何指针变量刚创建时,其内容是随机的,在内存中乱指一通。因此,使用指针前,一定要对其初始化,使其指向合法的内存,对于无处可指的指针,也要将其赋值为null。
2.指向临时变量的指针
当前代码块执行完毕后,代码块中声明的临时变量(包括函数调用时的参数)都会自动消亡,其占用的内存空间(栈内存)也被内存管理器收回。此时,指向这些临时变量的指针便没有了意义,使用这些指针会给程序造成不可预料的后果,见代码7.1。
代码7.1 返回指向临时变量的指针PointerToTemp
<————————————文件名:example701.cpp———————————————> 01 #include<iostream> 02 using namespace std; 03 char*GetStr() 04 { 05 char sz[]="Hello,C++";//字符数组sz,在函数内部创建,函数执行结束后, 06 //其对应的内存区域会被撤销 07 return sz; 08 } 10 int main() 11 { 12 char*p=GetStr();//返回字符数组的首地址给p 13 cout<<p<<endl;//用于p指向的内存被撤销,程序运行会出错 14 return 0; 15 }编译链接,编译器会给出如下警告。 warning C4172:returning address of local variable or temporary
输出结果如下所示。
↔
代码7.1 返回指向临时变量的指针,从中可以看出,程序并没有输出我们想要的“Hello,C++”,而是输出了乱码,这是由于指针p是野指针。在函数GetStr()内,声明了字符数组sz,编译器根据初始化字符串“Hello,C++”的长度为其分配了栈内存,并将数组名指针sz返回,但是,在函数GetStr()执行结束后,sz指向的内存空间已经撤销,因此,p的初始化实际是没有意义的,p并没有指向合法的内存空间,所以输出错误。