一、野指针
什么是野指针?
:所谓野指针就是,指针(地址)是一个随机值,这个随机值会指向任何可能的空间,这就是野指针。
野指针的危害?
:野指针可能会导致两种情况,这两种情况其实在前面描述过。
- (1)指针没有对应任何真实的存储空间
- (2)指向其它空间:
1)其它空间不允许操作
2)允许操作
这种最麻烦,可能会导致数据的篡改,而且还很难排查出错误。
int fun()
{
int *p;
*p = 200;
}
例子忘了给P
初始化,也忘了赋值,如果p
中的随机值恰好指向某个可以操作的空间,*p = 200
这句话是没问题的,但是很有可能把别的变量的空间给修改了
其实像这种野指针的问题,在开发时总会遇到个那么几次,如果在开发中不能将野指针排查出来的话,就会一直遗留到产品中,在用户使用的过程中,问题随时都可能爆发出来.
二、怎么解决野指针问题
1、在使用指针变量之前,记得赋值一个合法指针
int fun()
{
int *p;
p = malloc(siezof(int)); //p中有了合法指针后,就不会出现野指针的情况
*p = 200;
}
仅仅靠赋值这个方法,还不是很靠谱,因为很容易搞忘掉。
2、最好的办法,定义指针的时候就初始化
赋值确实很容易忘记,但是初始化却很容易想起,所以在定义指针变量的时候,要记得初始化。
1)初始化为你需要的指针
int a = 10;
int *p = &a;
2)如果不知道初始化为何值的话,就初始化为NULL
int *P = NULL;
有些时候确实不知道初始化为什么,因为需要在使用时才指定具体的指针,像这种情况的话,就初始化为NULL
指针。
初始化NULL
的好处?
:万一忘了赋值合法指针的话,解引用NULL
会导指针错误,在编程调试时,指针会导致程序被终止,程序员就回去排查错误,方便了程序员对指针错误的排查。
如果不初始化为NULL
的话,随机值可能指向了其它变量的空间,如果这个空间还可以操作的话,程序表面上会正常运行,但是可能篡改其它变量的数据,程序得不到正确的计算结果,这样的错误更难搞定。
3、更严谨的使用指针
如果更严谨一点的话,我们在使用应该加上if(NULL != p)的判断
int *p = NULL;
if(NULL != P)
{
*p = 200;
}
三、NULL指针
1、NULL宏被定义在什么地方
NULL
这个宏被定义在了C
标准库的stddef.h
中,定义形式如下:
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif
C++与C是兼容的,所以stddef.h既可以在C中使用,也能在C++中使用。在C中NULL为((void *)0),C++中为0.
这两种情况的值一样,唯一所不同的只是类型,0
的类型时int
,((void *)0)
的类型时void *
,至于为什么会有这样的区别,我们暂且不关心,现在只需要记住,在C
中NULL
为(void *)0
即可。
2、“0”地址
NULL
这个空指针就是0
地址,0
地址要么不对应实际空间,要么就是不能访问,所以对NULL
指针进行解引用时,会导致指针错误。
如果指针变量是全局变量的话,其实可以不用初始化NULL
,因为全局变量不初始化时,默认就是0
四、段错误
什么是段错误?
:这个实际上Linux
下指针错误的叫法,英文叫Segmentation fault
,翻译为中文就是“段错误”
为什么把指针错误叫做段错误?
:应该与程序的内存结构有关,因为程序的内存结构是由.text
、.rodata
、.data
、.bss
、堆、栈等组成,我们可以将.text
等称为Segment
(段),如果指针有问题的话,就可能会导致放问错误的Segment
,因为此就称为了段错误
例如:
#include <stddef.h>
int main(void)
{
int *p = NULL;
*p = 200;
return 0;
}
在Linux下直接报Segmentation fault
(段错误):
$ gcc main.c
$ ./a.out
Segmentation fault
而在Windows平台下会:
Process finished with exit code -1073741819 (0xC0000005)
五、大段错误和小段错误
1. 大段错误
指针所指向的空间不存在,这种就是大段错误
2. 小段错误
指针所指向的空间是存在的,但是由于访问权限有限制,比如想写数据,但是空间只允许读数据,
像这种权限所导致的指针错误,就是小段错误