详解C语言那些可怕的野指针
创始人
2025-05-03 00:20:40
0

[[415864]]

 一、什么是野指针?

指针是C语言的灵魂,同时也是很容易让人犯错的重难点,用错了指针将是一个灾难。

指针变量的本质是值,这个特殊的值是一个内存地址值,而合法的内存地址包括定义的变量的地址(栈)、malloc函数申请堆内存返回的地址(但未使用free释放,是在堆空间动态申请)

需要注意的是,野指针不是NULL指针,通常NULL指针可以使用if语句来判断,但是C语言中没有任何方法用来判断一个指针是否为野指针!

二、野指针是怎么来的?

通常野指针是因为指针变量中保存的值不是一个合法的内存地址或者指向不可用内存的指针而造成的。

而且野指针往往会造成内存越界、段错误等难以找到的问题,下面分几种情况来说说野指针的由来。

局部指针变量没有被初始化 

  1. //在win10_64位+vs2017  
  2. //来源:技术让梦想更伟大  
  3. //作者:李肖遥  
  4. #include   
  5. #include    
  6. struct Student  
  7. {  
  8.     char* name;  
  9.     int number;  
  10. };  
  11. int main()  
  12. {  
  13.     struct Student s;  
  14.     strcpy(s.name, "Lixiaoyao"); // OOPS!  
  15.     s.number = 99;  
  16.     return 0;  

局部变量不像全局变量那样,不赋值会自动初始化为0,指针name指向的内存空间地址是随机的,不能向随机地址空间写数据。我们在定义局部指针变量时应该初始化为NULL,局部变量则初始化为0

使用已经释放过后的指针 

  1. //在win10_64位+vs2017  
  2. //来源:技术让梦想更伟大  
  3. //作者:李肖遥  
  4. #include   
  5. #include   
  6. #include   
  7. void func(char* p)  
  8. {  
  9.     printf("%s\n", p);  
  10.     free(p);  
  11. }  
  12. int main()  
  13.     char* s = (char*)malloc(5);  
  14.     strcpy(s, "Lixiaoyao");//数组越界  
  15.     func(s);  
  16.     printf("%s\n", s); // OOPS!使用已经释放的指针s  
  17.     return 0;  

malloc申请的堆空间释放后,意味着把这片内存归还到空闲链表,其它程序可以使用这片空间,如果其它程序使用了这个空间,可能导致其它程序莫名其妙的被关闭,所以一定要在释放过后将指针变量的值赋值为NULL。

指针所指向的变量在指针之前被销毁 

  1. //在win10_64位+vs2017  
  2. //来源:技术让梦想更伟大  
  3. //作者:李肖遥  
  4. #include    
  5. char* func()  
  6. {  
  7.     char p[] = "Lixiaoyao";  
  8.     return p;  
  9. }  
  10. int main()  
  11. {  
  12.     char* s = func();  
  13.     printf("%s\n", s); // OOPS!  
  14.     return 0;  

func函数被调用的时候,栈区存放了局部数组p,func返回之后,栈顶指针退出,占用的内存已经被释放掉,此时指针s指向一个被释放掉了栈空间,如果栈空间值被修改了,就不会打印出预期结果,s就变成了一个野指针,所以我们绝对不要在函数中返回局部变量和局部数组的地址。

进行了错误指针运算 

  1. //在win10_64位+vs2017  
  2. //来源:技术让梦想更伟大  
  3. //作者:李肖遥  
  4. #include   
  5. void main()  
  6. {  
  7.  int a[10] = {1,2,3,4,5,6,7,8,9,10};  
  8.  int *p;  
  9.   for (int *p = &a[9];p >= a;){  
  10.     *--p = 0;  
  11.   }  

程序中在数组第1个元素a[0]被清除之后,指针p的值还继续减下去,而接下去的一次比较运算是用于结束循环的。但表达式p>= a(p >= &a[0])的值是未定义的。

为避免这种情况,一定要确保字符数组要以‘\0’结尾,为防止内存越界,自己编写的内存相关函数需要指定正确的长度信息。

进行了错误的强制类型转换 

  1. //在win10_64位+vs2017  
  2. //来源:技术让梦想更伟大  
  3. //作者:李肖遥  
  4. #include   
  5. #include   
  6. int main()  
  7. {  
  8.     int a = 1;  
  9.     int p = &a;  
  10.     printf("%d\n",*((int*)p));  
  11.     /*  
  12.     在64位下输出错误  
  13.     32位下输出a的值 1  
  14.     */  
  15.     return 0; 
  16.  } 

上面的程序在64位下输出错误,32位下输出a的值1,在我们写嵌入式程序的时候,会将int类型的一个数据强制转换成一个指针类型用来表示寄存器的地址,这个时候就需要注意了。

怎么避免野指针?

知道了野指针产生的原因,避免方法就出来了,在指针的解引用之前,确保指针指向一个绝对可用的空间。

  1.  定义指针时,同时初始化为NULL
  2.  在指针解引用之前,先去判断这个指针是不是Null
  3.  指针使用完之后,将其赋值为NULL
  4.  在指针使用之前,将其赋值绑定给一个可用地址空间 

 

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...