目录
[1. 野指针常见成因](#1. 野指针常见成因)
[1.1 指针未初始化](#1.1 指针未初始化)
[1.2 指针越界访问](#1.2 指针越界访问)
[1.3 指针指向的空间释放了](#1.3 指针指向的空间释放了)
[2. 规避野指针](#2. 规避野指针)
[2.1 指针初始化](#2.1 指针初始化)
[2.2 小心指针越界](#2.2 小心指针越界)
[2.3 指针变量使用前检查有效性,不再使用时及时置NULL](#2.3 指针变量使用前检查有效性,不再使用时及时置NULL)
[2.4 避免返回局部变量的地址](#2.4 避免返回局部变量的地址)
野指针:野指针就是指针指向的位置是不可知的(不正确的、随机的、没有明确限制的);
1. 野指针常见成因
1.1 指针未初始化
cpp
int main()
{
int* p; //局部变量未初始化,默认为随机值
*p=20;
}
注:p为局部变量,局部变量未初始化时默认为随机值;
1.2 指针越界访问
cpp
int main() {
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int* p = arr;
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i <= sz; i++) {
printf("%d ", *p);
p++;
}
return 0;
}
运行结果如下:
由于循环体循环了11次,当指针p指向的位置超出数组arr的范围时,p就是野指针;
1.3 指针指向的空间释放了
cpp
int* test() {
int a = 10;
return &a;
}
int main() {
int* p = test();
printf("%d\n", *p);
return 0;
}
变量a作为局部变量,离开函数test ( ) 范围即销毁,也就是a所在的内存地址已还给操作系统,此时再在main()函数中使用该地址访问数据,该地址就是野指针;
2. 规避野指针
2.1 指针初始化
1、 定义指针变量时,若明确知道指针指向的位置则直接赋值具体地址,
若不知道指针指向的位置则可赋值NULL:
cpp
int main() {
int a = 10;
int* p1 = &a;
*p1 = 20; // 正确
int* p2 = NULL;
// *p2 = 30; // 错误
return 0;
}
2、NULL是C语言中定义的一个标识符常量,值是0,0也是地址,但该地址无法使用,读写该地址会报错,NULL的定义如下:
cpp
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
2.2 小心指针越界
一个程序只能通过指针访问其向内存申请的那部分空间,不能超出范围访问,超出范围访问就是越界访问;
2.3 指针变量使用前检查有效性,不再使用时及时置NULL
cpp
int main() {
int* p = NULL;
// 对指针进行判NULL的有效性判断
if (p != NULL) {
*p = 20;
}
return 0;
}
2.4 避免返回局部变量的地址
比如1.3部分的示例:
函数test ( ) 内的变量a作为局部变量,离开test ( ) 函数范围即销毁,也就是a所在的内存地址已还给操作系统,此时再在main ( ) 函数中使用该地址访问数据,该地址就是野指针;