前面两文中内存错误释放以及错误访问指向栈的指针,从另外角度,其中一部分错误还可以归结为访问了野指针。野指针又称悬挂指针,代表那些指向不可用内存区域的指针。操作野指针,程序会发生难以预料的错误。形成野指针主要有以下原因:
1)指针没有初始化。指针变量创建时不会自动指向null,其缺省值是随机的,比如:
int *p;
*p = 0;
这种代码可能导致死机或者非法操作,所以使用指针前一定要初始化,使它指向分配好的可用空间,否则就成了野指针。
2)内存free后,指向内存的指针被误当作合法指针而继续使用。例如下例:
char *p = (char *) malloc(100);
strcpy(p, “hello”);
free(p); // p 所指的内存被释放,但是p所指的地址仍然不变
……
if(p != NULL) // 没有起到预防作用,因为p值未变
strcpy(p, “world”); // 出错,访问野指针
初学者在释放链表时也很容易犯类似错误:
while (p)
{
free(p);
q = p->next; //p已释放,p->next是访问野指针
p = q;
}
这里代码顺序很敏感,上面的顺序会导致野指针访问,正确方法是:
while (p)
{
q= p->next;
delete p;
p= q;
}
如果多个指针指向同一内存,这一问题也经常发生。free某个指针释放了内存,其他指针即刻被悬挂成为野指针,如果不注意而继续访问就会出错。
3)指针指向失效的栈内存,比如:某子函数返回一指针,此指针指向子函数内部某局部变量,子函数退出后,该局部变量所在的栈内存就因自动出栈而释放,而这个返回的指针也就成了野指针,不能再使用了。具体见下节例子。
总之,野指针和正常指针都指向某块内存,只是野指针所指的内存已不可用。就象一张失效的藏宝图,宝藏如果不在,藏宝图自然就成了废纸一张。所谓的悬挂也是表达类似含义。另外要注意区分野指针和空指针概念:野指针不特指空指针,而是指向垃圾(不可用)内存的指针。可以用if(ptr==null)预防空指针,但对野指针不起作用。所以野指针比空指针更隐蔽,危害更大。
思考下,内存重复free的错误是不是第二次free访问了野指针?大家可以发表意见。