一、野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。
#include <stdio.h>
int main(void)
{
int *p;//当前的p就是野指针
*p=4;
//报错 运行时的段错误,由野指针造成
}
二、野指针出现的三种情况
1. 指向不可访问的地址:比如内核空间(每个进程都认为自己有4G的运行空间,但进程是共享4G空间,在每个进程可以寻址的范围内有一部分是操作系统的空间),结果是触发段错误。
2. 指向一个可用的且没有特别意义的空间:比如曾经使用过但无用的在栈、堆空间,结果是没有报错,但是有很大的隐患。
3. 指向了一个可用的空间,但这个空间在程序中正在被使用:比如是程序的一个变量,那么这个野指针的解引用会刚好修改这个变量的值,导致变量被莫名其妙的改变,导致程序出现离奇多的错误,最终程序崩溃或者数据被损害,这种危害最大的情况。
为什么加了printf函数后野指针就只可能发生后两种情况呢
因为printf函数是一个复杂函数,不停的申请栈,栈使用完没有被擦除。
指针变量如果是局部变量则分配在栈上,反复使用不会被擦除,所以是脏的。栈的使用多少会影响默认值,因此野指针的值是有一定规律不是完全随机。
三、如何避免野指针
指针没有明确的指向一个可用的内存空间,然后去解引用导致了野指针。
在指针的解引用之前确保指针指向一个绝对可用的空间,能够避免野指针。
1. 定义指针时同时初始化为NULL。
2 . 在指针解引用之前,先去判断这个指针是不是NULL。
3. 在指针使用完之后,将其赋值为NULL。
4. 在指针使用之前将其赋值绑定给一个可用地址空间。
#include <stdio.h>
int main(void)
{
int a;
int *p=NULL;
int *p=&a;
//中间省略400行.......
if (NULL !=P)
{
*P=4;
}
p=NULL;//使用完后将指针重新定义为NULL
}
实践中的处理方法,在中小型程序中不必严格参照这个标准,但在大型程序中建议严格参考这个原则。
NULL究竟是个什么
NULL在c中定义为:
#ifdef _cplusplus
#define NULL 0//在c++中NULL就是0
#else
#define NULL (void *)0//在c中NULL是强制类型转化为(void *)的0
#endif
在c中int *p;你可以p=(int *)0,但不可以p=0,因为c严格要求类型相同。
NULL的实质就是0,将指针赋初值给NULL,其实就是将指针指向0地址处。原因有两个:
1. 0地址是一个特殊地址,我们认为指针指向这个地址的为野指针。
2. 这个地址在一般的操作系统中都是不可被访问的,如果没按规章处理就会触发段错误,触发段错误已经是野指针造成的最小错误了。
判断野指针语句
写成 if (NULL != P),而不是写成if (p != NULL)
原因是如果NULL写在后面当中间是==号时容易写出=运算符,编译器不会报错,错误很难检查出来。所以一般把NULL写在运算符前面。