“野指针并不是指向NULL的指针,而是指向不确定地址的指针。由于其指向地址的不确定性,系统通过该指针访问的地址很可能是无法访问的,导致系统发生严重错误,即使可以被访问,读取到的数据往往也是错误的,因此野指针对程序系统运行的危害是致命的。”
我们在代码中经常通过判断指针地址是否为NULL来确定该指针指向的地址是否可以访问,比如以下代码:
float *p = (float *)malloc(5*sizeof(float));
if(p != NULL)
{
p[0] = 1.1;
}
那么如果指针p是野指针呢,p指向的不是NULL而是不确定的地址,该地址很可能是“垃圾”内存,此时则不能通过判断其是否为NULL来确定其指向的地址是否可以正常读写。因此我们编写代码时应尽量避免野指针的出现。
01
—
指针变量没有被初始化
C/C++中,指针变量被创建时,系统不会自动将其初始化为NULL或其它确定地址,如果程序员不将其初始化为NULL或其它确定地址,它将指向一个不确定的地址,这个地址有可能不存在,即使存在也有可能是非法地址而无法被访问。所以,要么将其赋值为NULL,要么将其指向一个确定的合法地址:
uchar *a = NULL;
float *p = (float *)malloc(5*sizeof(float));
02
—
指针被free或delete之后未赋值为NULL
这种情况多出现在全局指针:
1. 某指针变量p是一个全局变量;
2. p在某个地方(比如某个函数里面)被设置为指向一个合法的内存地址;
3. 接着在另一个地方(比如另一个函数内)将p指向的地址释放内存,但不将p初始化为NULL。此时p原先指向的内存地址将不能被正常访问。
4. 在别的地方通过判断p是否为NULL来确定其指向的地址是否可以访问,实际上p不是NULL但它指向的地址也无法被访问,导致程序出错。
char *p; //全局指针变量
void func_a(void)
{
p = (char *)malloc(10); //将p指向合法的可访问的地址
}
void func_b(void)
{
free(p); //释放p指向的内存地址,但不将p设置为NULL,p变成野指针
}
void func_c(void)
{
if(p != NULL) //p不为NULL,且p指向的地址已无法被正常访问,但程序判断结果还是true,然后访问p原先指向的地址,导致出错
{
p[0] = 1;
p[1] = 2;
}
}
int main(void)
{
func_a();
func_b();
func_c();
return 0;
}
所以,应该在free之后将p赋值为NULL就好了:
void func_b(void)
{
free(p);
p = NULL;
}
03
—
指针指向生命周期已经结束的变量
有时候指针p指向的变量a已经结束生命周期,然而p未被赋值为NULL,但是还是通过指针p来访问变量a的值,将导致程序出错,比如以下代码,变量a的生命周期仅仅在函数func运行结束之前,当func运行结束之后,变量a将被销毁,p则变成野指针。
char *p;
void func(void)
{
char a = 10;
p = &a; //将变量a的地址赋值给p,也即将p指向a的地址
}
int main(void)
{
func();
printf("p指向的变量a的值为:%d\n", *p);
return 0;
}
这种情况是最难预防的,而且也很不好定位bug,所以我们编程的时候还是要尽量注意变量的有效范围。
欢迎扫码关注以下微信公众号,接下来会不定时更新更加精彩的内容噢~
点击进入留言区