首先要搞懂什么是野指针?野指针是怎么发生的?然后学会避免野指针的发生。
野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。
野指针怎么发生的?
指针变量在定义时如果未初始化,值不是空的,值是随机的。即int* p;
此时定义了指针p,但并未指定初始化。那么编译器会分配给指针p变量一个随机的地址。指针变量的值其实就是指针所指向的那个变量的地址,所以意味着这个指针指向了一个地址是不确定的地址,这时候去解引用就是去访问这个地址不确定的变量,所以结果是不可知的。
因为野指针的指向地址是不可预知的,所以有以下3种情况
- 第一种是指向不可访问(操作系统不允许访问的敏感地址,譬如内核空间)的地址,访问时会抛出Sgmentation fault异常,这种算是最好的情况了,因为我们能够清楚意识到发生了错误。
- 第二种是指向一个存在的、可用的、但没什么特别意义的空间(即我们曾经使用过但是已经不用的空间),这时候程序运行不会出错,也不会对当前程序造成损害,这种情况下会掩盖你的程序错误,让你以为程序没问题,其实是有问题的。
- 第三种情况是指向了一个存在的、可用的、仍然在用的空间,这个空间在程序中正在被使用或者说将来被使用。与其他页面存在关联关系,那么野指针的解引用就会刚好修改这个变量的值,导致这个变量莫名其妙的被改变,程序出现离奇的错误。工般最终都会导致程序崩溃,或者数据被损害,这种错误是最难预知的,潜伏期极长,是三种情况中危害最大的。
指针变量如果是局部变量,则分配在栈上,本身遵从栈的规律(反复使用,使用完不擦除,所以是脏的,本次在栈上分配到的变量的默认值是上次这个栈空间被使用时余留下来的值),就决定了栈的使用多少会影响这个默认值。因此野指针的值是有一定规律不是完全随机,但是这个值的规律对我们没意义。因为不管落在上面野指针3种情况的哪一种,都不是我们想看到的。
怎么避免野指针?
野指针的错误来源就是指针定义了以后没有初始化,也没有赋值,导致了指针没有明确的指向一个可用的内存空间。
知道了野指针产生的原因,随之就可总结出避免野指针的方法。即在指针的解引用之前,确保指针指向一个绝对可用的空间。
常规的做法是:
- 定义指针时,同时赋值为NULL或nullptr。
- 在指针解引用之前,先去判断这个指针是不是为空。
- 指针使用完之后,将其赋值为NULL或nullptr。
具体情况具体分析,指针地址随机也可能是另外的原因。可见文章: 结构体/类/指针里的成员没有正常初始化的问题 - 麦瑞克博客 (unitymake.com)