一文搞懂C/C++的野指针

野指针并不是指向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,所以我们编程的时候还是要尽量注意变量的有效范围。

欢迎扫码关注以下微信公众号,接下来会不定时更新更加精彩的内容噢~

点击进入留言区

posted @ 2021-05-19 00:03  萌萌哒程序猴  阅读(412)  评论(0编辑  收藏  举报