【C语言进阶深度学习记录】三十七 C/C++中造成程序内存错误的原因(野指针)

什么是野指针? 指针变量存的地址是一块非法内存地址。进而形成野指针。但是需要注意一点,野指针不是NULL指针。

文章目录

    • 1 野指针的概念
      • 1.1 野指针代码案例初探
    • 2 如何避免野指针
      • 2.1 野指针代码案例分析进阶
    • 3 总结

1 野指针的概念

  • 野指针变量中的值是非法内存地址,进而形成野指针
  • 野指针不是NULL指针,是指向不可用内存的地址的指针
  • NULL指针并无危害,很好判断,也很好调试
  • C语言的语言层面无法判断一个指针所保存的地址是否是合法的。

那么野指针是如何产生的呢?

以下在代码中的编程不规范会导致野指针的产生:

  1. 局部指针变量没有被初始化(我们知道局部变量不初始化就是随机值,所以如果局部指针被赋为随机值,那么这个随机值所代表的地址很有可能是不能访问的,是非法的地址。那么它就是野指针)
  2. 指针所指向的变量在指针被使用之前被销毁。比如在函数的返回值是指针。在函数返回后,函数的调用栈就被销毁了,接着使用被返回的指针时,这个指针所指向的内存已经被销毁,所以形成野指针
  3. free指针后,还依然使用指针,这也是野指针
  4. 进行了错误的指针运算和错误的强制类型转换(后面代码案例会分析)

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编译器编译上述代码:上述代码编译没有问题,运行会出现段错误。如果使用较新版本的编译器,可能编译都会直接报错。
  • 分析错误原因:

段错误一般就是野指针问题:

  1. 首先第8行将1234567强制转换为int*指针变量并赋值给p2。然后在第29行使用p2。1234567这个地址,肯定是不能访问的。所以p2就是野指针。所以运行时访问p2指针指向的内存就会产生段错误
  2. 16行已经将指针p1的内存释放。但是在20行又使用p1.这也是野指针,会造成段错误
  3. 第13行中,因为p1在第7行只申请了40字节也就是10个int的内存。所以13行使用p1加了40次,肯定会越界访问了本不是p1申请的内存。这也会造成段错误

2 如何避免野指针

遵循以下几条规则,避免野指针的产生

  1. 绝不在函数中返回局部指针变量或者局部数组
  2. 任何变量在定义后,必须先初始化
  3. 字符数组必须确认最后一个元素是‘\0’结束符才能将该数组当成是字符串,否则不能将其当成字符串。因为字符串的所有操作都是基于最后的’\0’结束符,如果没有这个结束符,很有可能在操作字符串的时候产生内存越界
  4. 任何使用与内存操作相关的函数必须指定长度信息。在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 总结

  • 知道野指针的由来以及如何避免产生野指针。这是非常重要的!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/422771.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法补充 2011-9-12

设计一个算法将顺序表L中所有小于0的整数放前半部分&#xff0c;大于等于0的整数放在后半部分二叉树的删除设计一个算法将顺序表L中所有小于0的整数放前半部分&#xff0c;大于等于0的整数放在后半部分 思路:从左侧找出>0的元素&#xff0c;从右侧找出<0的元素,然后进行交…

【C语言进阶深度学习记录】三十八 C/C++语言中的函数声明与函数定义

文章目录1 函数的声明和定义1.1 代码分析2 总结1 函数的声明和定义 声明的意义在于告诉编译器程序单元的存在。只是告诉编译器它存在但是不在声明这里定义&#xff0c;有可能在当前文件中的其他地方或者其他文件中定义。如果在它还没有被定义之前就使用它&#xff0c;会导致编…

ASP.NET MVC3 系列教程 - 部署你的WEB应用到IIS 6.0

I:ASP.NET MVC3 部署的前期工作 1.确认部署的服务器操作系统环境 首先我们确认服务器的操作系统版本可以从系统命令行工具里输入: systeminfo 获取相关操作系统信息例如然后再确认IIS版本信息 -> 打开IIS管理工具即可接着确认.NET Framework的版本可以在系统命令行工具执行:…

【C语言进阶深度学习记录】三十九 C语言中的可变参数(参数可变的函数)

用过printf()函数的热都知道&#xff0c;printf的参数可以有多个&#xff0c;它是可变的&#xff0c;根据我们输出参数的类型以及个数的不同来确定参数。今天来学习C语言中参数可变的函数是如何实现的。 文章目录1 可变参数2 总结1 可变参数 首先我们要明白一点&#xff0c;在…

Linux 安装 OpenOffice

继续弃W从L的奋斗&#xff01;哈哈 在RedHat 6 上安装 OpenOffice。 首先在官网上下载OpenOffice的软件包 100多M。软件包名为&#xff1a;OOo_3.3.0_Linux_x86_install-rpm_en-US.tar.gz 下好后开始安装软件&#xff1a;1 解压 tar xjvf OOo_3.3.0_Linux_x86_install…

【离散数学中的数据结构与算法】一 最大公约数与最小公倍数之间的关系

文章目录1 算数基本定理2 最大公约数3 最小公倍数4 性质5 推论1 算数基本定理 设正整数 n>1&#xff0c; 则 n 可唯一地表示为&#xff1a; 其中 p1<p2<,…, <ps 是 s 个相异的素数&#xff0c; 指数ki都是正整数。 此定理又称作唯一析因定理&#xff08;unique f…

Item 添加事件 list grally等

mainListView.setOnItemClickListener (new OnItemClickListener(){ public void onItemClick(AdapterView<?> parent,View v,int position,long id){ } });转载于:https://www.cnblogs.com/sode/archive/2011/09/25/2189845.html

【离散数学中的数据结构与算法】二 欧几里得算法与裴蜀等式

欧几里得算法是计算两个数最大公因子算法。又称辗转相除法。本文将学习为什么辗转相除法可以求得两个数的最大公因子。同时也可以根据最大公因子计算两个数的最小公倍数。 文章目录1 欧几里得算法的理论基础1.1 欧几里得算法&#xff08;辗转相除法&#xff09;2 裴蜀等式&…

数据库-存储过程-游标-函数

一、存储过程 SQL99标准提出的SQL-invoked-rountines的概念&#xff0c;它开分为存储过程与函数&#xff0c;这里首先介绍存储过程 存储过程分为三类&#xff1a;系统存储过程(如&#xff1a;sp_help)、自定义存储过程、扩展存储过程 存储过程可以理解为一个SQL语句块&am…

【离散数学中的数据结构与算法】四 加法法则与乘法法则

文章目录1 加法法则2 乘法法则3 例子3.1 例一3.2 例二3.3 例三4 总结1 加法法则 加法法则&#xff1a; 设事件 A 有 m 种产生方式&#xff0c; 事件 B 有n 种产生方式&#xff0c;则当 A 与 B 产生的方式不重叠时&#xff0c;“事件 A 或 B 之一” 有 mn 种产生方式。 加法法…

实现上移的存储过程

--上移存储过程 create proc sp_sort id int as declare SortID int --排序位置 declare TempSortID int --临时排序位置 declare TempID int --临时编号 begin transaction select SortIDSortID from [User] where [ID]ID --找出想修改顺序的用户的当前当前排序 select Tem…

前端学习(310):清除浮动的方法

我们经常把高度塌陷问题也叫做常见的几种清除浮动的方法 高度塌陷问题—父元素高度自适应&#xff0c;子元素float后&#xff0c;造成父元素高度为0&#xff0c;就叫做高度塌陷问题 给父元素一个高度 缺点&#xff1a;无法高度自适应 父元素{overflow:hidden;} 缺点&#xf…

【离散数学中的数据结构与算法】五 排列与组合一

在leetcode刷题过程中&#xff0c;遇到过很多关于排列组合的问题。弄清楚排列组合的相关原理&#xff0c;是非常有用处的。 文章目录1 问题2 排列-有序选取2.1 重复选取-可重排列2.2 不重复选取-排列2.21 全排列3 例题4 总结1 问题 设集合S包含n个元素&#xff0c;从S中选取r个…

Google Maps 地址转化成坐标

http请求格式http://maps.google.com/maps/geo?q查询关键字&outputkml(输出格式可以 为xml kml json)&oeutf8&sensortrue或者false&key你的apikey示例http://maps.google.com/maps/geo?q湖南大学软件学院&outputkml&keyabcdefg(api key)输出kml文件如…

【离散数学中的数据结构与算法】六 排列与组合二

接着上一篇学习&#xff1a;【离散数学中的数据结构与算法】五 排列与组合一 上一篇文章主要学习了可重复选取的可重排列和不可重复选取的排列。他们都是在n个不同的对象中选取。 今天我们俩学习的是&#xff0c;当这个n个对象中有相同的元素的时候&#xff0c;排列的相关定理…

sql 2008 使用output避免数据修改后的二次查询

表a (f1 primary key,f2,f3), 表b (f1,f3,f4)现要根据表b修改表a中的相应字段的值&#xff0c;并将修改过的值显示出来&#xff0c;一般用法&#xff1a;1 update a from b set a.f3b.f3 where a.f1b.f12 select a.f1,f2,f3 from a where a.f1 in (select f1 from b)根据sql的…

【离散数学中的数据结构与算法】七 排列与组合三

前两篇文章学习了不可重复选取的排列与可重复选取的可重排列。本篇文章开始学习组合的相关定理。 文章目录1 组合1.1 组合的计算公式2 总结1 组合 跟排列一样。组合也分为不重复选取的组合&#xff0c;与可重复选取的可重组合。本节内容主要学习不可重复选取的组合 从 n 个不…