1. 简介
- C/C++指针常常让程序员很头疼。本文详细介绍C/C++的空指针和野指针。
2. 空指针
-
NULL指针,他作为一个特殊的指针变量,让它指空,表示不指向任何地址。
-
对一个NULL指针解引用是一个非法的操作,所以在对指针解引用之前必须确保它不是一个NULL指针。
if (p != NULL) { *p = 1; //如果指针不为空指针,则对指针进行操作 } else { return 0; //空指针,退出 }
3. C++11中的空指针
- C++11引入了nullptr关键字来表示指针空值。
- 用0和NULL表示空指针会产生歧义,建议用nullptr表示空指针,也就是(void*)0
int main() { //空指针定义 int* p1 = NULL; int* p2 = 0; //推荐 int* p3 = nullptr; return 0; }
- 为了提高代码的健壮性,在后续表示指针空值时建议最好使用 nullptr 。
- nullptr是对NULL的一个升级,因此在以后的初始化空指针时,建议大家使用nullptr。
4. 空指针的使用场景
4.1 指针初始化为空指针
-
在良好的C/C++编程习惯中,声明一个变量时最好给这个变量赋一个合适的初始值,否则就有可能出现不可预料的错误。
-
在C++中创建指针时,如果没有给指针初始化,计算机将分配用来存储地址的内存(指针的内存),但不会分配用来存储指针所指向的的数据的内存。
int* p; //分配用来存储地址的内存(分配指针的内存),这里并不知道指针指向哪块内存 *p = 1; //给指针指向的内存赋值
-
上述代码中没有赋予指针所指向的数据的内存,会照成难以预料的后果。
-
为了避免这个问题,我们都要给指针进行初始化。通常我们都是这样来初始化指针的。
int main() { //空指针定义 int* p1 = NULL; //创建p1指针;p1指空,表示不指向任何地址。 int* p2 = 0; //推荐 int* p3 = nullptr; return 0; }
4.2 操作指针之前判断指针是否为空
-
在程序中要增加判断指针是否为空的代码,防止对空指针解引用造成系统崩溃,增强函数的健壮性
if (p != NULL) { *p = 1; //如果指针不为空指针,则对指针进行操作 } else { return 0; //空指针,退出 }
5. 野指针
-
野指针,也就是指向不可用内存区域的指针。如果对野指针进行操作,将会使程序发生不可预知的错误,甚至可能直接引起崩溃 。
-
野指针不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是野指针是很危险的,也具有很强的掩蔽性,if语句对它不起作用。
-
造成野指针的常见原因有三种:
-
指针变量没有被初始化 。任何指针变量刚被创建时不会自动成为NULL指针。在Debug模式下,VC++编译器会把未初始化的栈内存上的指针全部填成 0xcccccccc ,当字符串看就是 “烫烫烫烫……”;会把未初始化的堆内存上的指针全部填成 0xcdcdcdcd,当字符串看就是 “屯屯屯屯……”。把未初始化的指针自动初始化为0xcccccccc或0xcdcdcdcd,而不是就让取随机值,那是为了方便我们调试程序,使我们能够一眼就能确定我们使用了未初始化的野指针。在Release模式下,编译器则会将指针赋随机值,它会乱指一气。所以,指针变量在创建时应当被初始化,要么将其设置为NULL,要么让它指向合法的内存。
-
指针指向的内存被释放了,而指针本身没有置NULL 。对于堆内存操作,我们分配了一些空间(使用malloc函数、calloc函数或new操作符),使用完后释放(使用free函数或delete操作符)。指针指向的内存被释放了,而指针本身没有置NULL。通常会用语句if (p != NULL)进行防错处理。很遗憾,此时if语句起不到防错作用。因为即便p不是NULL指针,它也不指向合法的内存块。所以在指针指向的内存被释放后,应该将指针置为NULL。
-
指针超过了变量的作用范围 。即在变量的作用范围之外使用了指向变量地址的指针。这一般发生在将调用函数中的局部变量的地址传出来引起的。这点容易被忽略,虽然代码是很可能可以执行无误,然而却是极其危险的。局部变量的作用范围虽然已经结束,内存已经被释放,然而地址值仍是可用的,不过随时都可能被内存管理分配给其他变量。