什么是野指针? 指针变量存的地址是一块非法内存地址。进而形成野指针。但是需要注意一点,野指针不是NULL指针。
文章目录
- 1 野指针的概念
- 1.1 野指针代码案例初探
- 2 如何避免野指针
- 2.1 野指针代码案例分析进阶
- 3 总结
1 野指针的概念
- 野指针变量中的值是非法内存地址,进而形成野指针
- 野指针不是NULL指针,是指向不可用内存的地址的指针
- NULL指针并无危害,很好判断,也很好调试
- C语言的语言层面无法判断一个指针所保存的地址是否是合法的。
那么野指针是如何产生的呢?
以下在代码中的编程不规范会导致野指针的产生:
- 局部指针变量没有被初始化(我们知道局部变量不初始化就是随机值,所以如果局部指针被赋为随机值,那么这个随机值所代表的地址很有可能是不能访问的,是非法的地址。那么它就是野指针)
- 指针所指向的变量在指针被使用之前被销毁。比如在函数的返回值是指针。在函数返回后,函数的调用栈就被销毁了,接着使用被返回的指针时,这个指针所指向的内存已经被销毁,所以形成野指针
- free指针后,还依然使用指针,这也是野指针
- 进行了错误的指针运算和错误的强制类型转换(后面代码案例会分析)
1.1 野指针代码案例初探
- 代码41-1.c
#include <stdio.h>
#include <malloc.h>int main()
{int* p1 = (int*)malloc(40);int* p2 = (int*)1234567;int i = 0;for(i=0; i<40; i++){*(p1 + i) = 40 - i;}free(p1); for(i=0; i<40; i++){p1[i] = p2[i];}return 0;
}
- 使用gcc4.4.5编译器编译上述代码:上述代码编译没有问题,运行会出现段错误。如果使用较新版本的编译器,可能编译都会直接报错。
- 分析错误原因:
段错误一般就是野指针问题:
- 首先第8行将1234567强制转换为int*指针变量并赋值给p2。然后在第29行使用p2。1234567这个地址,肯定是不能访问的。所以p2就是野指针。所以运行时访问p2指针指向的内存就会产生段错误
- 16行已经将指针p1的内存释放。但是在20行又使用p1.这也是野指针,会造成段错误
- 第13行中,因为p1在第7行只申请了40字节也就是10个int的内存。所以13行使用p1加了40次,肯定会越界访问了本不是p1申请的内存。这也会造成段错误
2 如何避免野指针
遵循以下几条规则,避免野指针的产生
- 绝不在函数中返回局部指针变量或者局部数组
- 任何变量在定义后,必须先初始化
- 字符数组必须确认最后一个元素是‘\0’结束符才能将该数组当成是字符串,否则不能将其当成字符串。因为字符串的所有操作都是基于最后的’\0’结束符,如果没有这个结束符,很有可能在操作字符串的时候产生内存越界
- 任何使用与内存操作相关的函数必须指定长度信息。在C语言中,长度信息很重要,它往往是变量类型的一部分。如数组。如下图:
2.1 野指针代码案例分析进阶
- 代码41-2.c
#include <stdio.h>
#include <string.h>
#include <malloc.h>struct Student
{char* name; //这里有指针,很容易忘记初始化int number;
};char* func()
{char p[] = "D.T.Software";return p; //返回局部数组/指针,gcc4.4.5编译器会编译警告
}void del(char* p)
{printf("%s\n", p);free(p); //free之后要将p置NULL
}int main()
{struct Student s; //s中有指针变量,这里没有初始化,容易产生野指针char* p = func(); // 返回的指针指向的内存已经被销毁strcpy(s.name, p); //p指向的内存已经被销毁不能使用,且s中的name指针没有初始化也会产生野指针s.number = 99;p = (char*)malloc(5);strcpy(p, "D.T.Software"); //内存越界del(p);return 0;
}
- 上述代码编译就会产生警告。警告第15行返回局部指针。程序运行产生段错误
- 其他的会产生野指针的地方在代码中已经详细的说明。自己分析即可。
3 总结
- 知道野指针的由来以及如何避免产生野指针。这是非常重要的!!!