关于野指针的一些问题与总结

2023-11-09

void  Test( void )
{
char   * str  =  ( char   * ) malloc( 100 );
strcpy(str, “hello”);
free(str);    
if (str  !=  NULL)
{
  strcpy(str, “world”);
  printf(str);
}

 请问运行Test函数会有什么样的结果?
答:篡改动态内存区的内容,后果难以预料,非常危险。因为free(str);之后,str成为野指针,if(str != NULL)语句不起作用。


1.何为野指针?

野指针指指向一个已删除的对象或未申请访问受限内存区域的指针。与空指针不同,野指针无法通过简单地判断是否为NULL避免,而只能通过养成良好的编程习惯来尽力减少。对野指针进行操作很容易造成程序错误。

解释一下:

malloc 和 free 是在系统的堆上分配空间。
malloc是申请,意思就是告诉系统,我要用一块RAM,给我用了别人就不要用了。
free是释放,意思是告诉系统,给我的这块RAM我用完了,不再用了,系统可以把它干别的了。free()释放的是指针指向的内存。并不是说,free()解除了原来指向这块内存的指针与这块内存地址之间的联系,联系依然存在,这就可能导致误用出错,所以需要在free之后置NULL,这样就解除关联了。举个例子就是,A跟妻子离婚了,但A和她曾经是夫妻,曾经关系很亲密,这种关系不会随着离婚而改变,这是客观的,离婚了即free,A不能再去骚扰前妻,否则就是违法,A要是再想干那啥,A会坐牢的!!!
free之后,系统还没有拿这块RAM干别的事之前,这块RAM的内容可能是不会变的,依然可以读出原来的内容,因为你的指针a还是指向这块RAM。但要注意,这块RAM已经不属于你了,读一下内容无所谓,如果往里面写就很危险了。

2.成因

通俗说法:

 如果程序定义了一个指针,就必须要立即让它指向一个我们设定的空间或者把它设为NULL,如果没有这么做,那么这个指针里的内容是不可预知的,即不知道它 指向内存中的哪个空间(即野指针),它有可能指向的是一个空白的内存区域,可能指向的是已经受保护的区域,甚至可能指向系统的关键内存,如果是那样就糟 了,也许我们后面不小心对指针进行操作就有可能让系统出现紊乱,死机了。所以我们必须设定一个空间让指针指向它,或者把指针设为NULL,这是怎么样的一 个原理呢,如果是建立一个与指针相同类型的空间,实际上是在内存中的空白区域中开辟了这么一个受保护的内存空间,然后用指针来指向它,那么指针里的地址就 是这个受保护空间的地址了,而不是不可预知的啦,然后我们就可以通过指针对这个空间进行相应的操作了;如果我们把指针设为NULL,我们在头文件定义中的 #define NULL 0 可以知道,其实NULL就是表示0,那么我们让指针=NULL,实际上就是让指针=0,如此,指针里的地址(机器数)就被初始化为0了,而内存中地址为0 的内存空间……不用多说也能想象吧,这个地址是特定的,那么也就不是不可预知的在内存中乱指一气的野指针了。

  还应该注意的是,free和delete只是把指针所指的 内存给释放掉,但并没有把指针本身干掉。指针p被free以后其地址仍然不变(非NULL),只是该地址对应的内存是垃圾,p成了“野指针”。如果此时不 把p设置为NULL,会让人误以为p是个合法的指针。用free或delete释放了内存之后,就应立即将指针设置为NULL,防止产生“野指针”。内存 被释放了,并不表示指针会消亡或者成了NULL指针。(而且,指针消亡了,也并不表示它所指的内存会被自动释放。)

指针变量未初始化

任何 指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。

指针释放后之后未置空

有时 指针在free或delete后未赋值 NULL,便会使人以为是合法的。别看free和delete的名字(尤其是delete),它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。此时指针指向的就是“垃圾”内存。释放后的指针应立即将指针置为NULL,防止产生“野指针”。

指针操作超越变量作用域

不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。示例程序如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class  A {
public :
   void  Func( void ){ cout << “Func of  class  A” << endl; }
};
class  B {
public :
   A *p;
   void  Test( void ) {
     A a;
     p = &a;  // 注意 a 的生命期 ,只在这个函数Test中,而不是整个class B
   }
   void  Test1() {
   p->Func();  // p 是“野指针”
   }
};
函数 Test1 在执行语句 p->Func()时,p 的值还是 a 的地址,对象 a 的内容已经被清除,所以 p 就成了“野指针” 。

3.规避

在养成这些习惯的情况下,野指针的危害是可以降低的:
如:int* pInteger=NULL;//指针定义处
...
if(pInteger != NULL)
{
free(pInteger);
pInteger=NULL;//指针释放之后并不为空,要设置其为空
}
pInteger=(int*)malloc(10*sizeof(int));
if(pInteger != NULL)
{
printf("内存申请成功/n!");
exit(0);
}
...

初始化时置 NULL

指针变量一定要 初始化为NULL,因为任何指针变量刚被创建时不会自动成为NULL指针,它的 缺省值是随机的。

释放时置 NULL

当指针p指向的内存空间释放时,没有设置指针p的值为NULL。delete和free只是把内存空间释放了,但是并没有将指针p的值赋为NULL。通常判断一个指针是否合法,都是使用if语句测试该指针是否为NULL。例如:
1
2
3
4
5
6
7
8
9
int  *p=newint(6);
delete  p;
// 应加入 p=NULL; 以防出错
// ...
if (p != NULL)
{
   *p=7;
   cout << p << endl;
}
对于使用 free 的情况,常常定义一个宏或者函数 xfree 来代替 free 置空指针:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define xfree(x) free(x); x = NULL;
// 在 C++ 中应使用 nullptr 指代空指针
// 一些平台上的 C/C++ 已经预先添加了 xfree 拓展,如 GNU 的 
 
libiberty
xfree(p);
// 用函数实现,例如 GitHub 上的 AOSC-Dev/Anthon-Starter #9:
static  inline  void  *Xfree( void  *ptr) {
     free (ptr);
#ifdef __cplusplus
     return  nullptr ;
#else
     return  NULL;
#endif
}
q=Xfree(q);
所以动态分配内存后,如果使用完这个动态分配的内存空间后,必须习惯性地使用delete操作符取释放它。
关于函数使用需要注意的一些地方: 

A、申请了内存空间后,必须检查是否分配成功。 

B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。 

C、这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会 

出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。 

D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一 

些编译器的检查。 

4.相关链接

http://www.cnblogs.com/viviwind/archive/2012/08/14/2638810.html

http://blog.chinaunix.net/uid-24227137-id-3270110.html








本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于野指针的一些问题与总结 的相关文章

  • 使用valgrind检查内存问题并且输出报告

    valgrind内存泄漏分析 是在linux中检查内存泄漏的工具 当程序编写完之后我一般都会使用它来检查一次内存问题 基本上能杜绝服务器的内存泄漏问题 当然是面对C C 这样的语言的 使用方式就是将程序编译好 然后通过valgrind来启动
  • 内存管理解析(2) 字节对齐详解

    很想贴出转载链接 找不到原来看的资料了 只有从个人记录的笔记上挪过来 如有错误请留言指正 目录 一 什么是字节对齐 二 为什么要字节对齐 三 有哪些对齐形式 1 结构体对齐 对齐值 对齐准则 对齐的隐患 更改对齐方式 2 栈内存对齐 3 位
  • Java内存区域(栈、堆、方法区)详细解说

    参考文献 深入学习java虚拟机 概览 java虚拟机在执行java程序的过程中会把它所管理的内存划分成若干个不同的数据区域 这些区域各有用途 以及创建和销毁的时间 有的区域随着虚拟机的进程的启动而存在 有的则依赖用户线程的启动和结束而建立
  • C/C++中二级指针传递参数【个人遇到内存值发生改变现象的记录及相关修正方法】

    目录 0 前言 1 二级指针传参奇怪现象 2 分析 3 解决方法 0 前言 在c c 中 时常会使用到主调函数通过参数去获取被调函数中的数值情况 针对这种情况 我前面也写过C C 主调函数从被调函数中获取 各种类型 数据内容方式的梳理归纳文
  • linux内核中GPIO的使用(一)--IO内存

    一 相关概念 使用IO内存将物理地址映射为虚拟地址 再通过对虚拟地址的操作来控制硬件 所谓的IO内存是指一种编址方式 不同cpu平台使用的编址方式不同 一种是 IO内存 方式 也叫统一编址方式 是指内存和外设的地址是在同一个地址空间上的 如
  • C++内存泄漏和内存碎片的产生及避免策略

    1 内存泄漏的定义 一般我们常说的内存泄漏是指堆内存的泄漏 堆内存是指程序从堆中分配的 大小任意的 内存块的大小可以在程序运行期决定 使用完后必须显示释放的内存 应用程序一般使用malloc realloc new等函数从堆中分配到一块内存
  • C语言编程中的8位、16位、32位整数的分解与合并

    在单片机的编程中对于8位 16位 32位整数的分解与合并用的比较多 今天做了简要学习 后面还需要加以总结 练习在VC 6 0编程环境中进行 源程序 include
  • DDR一些引脚说明

    信号名 方向 功能描述 CK t CK c Input 差分时钟输入 所有的地址 控制信号都是通过CK t的上升沿与CK c的下降沿进行采样的 CKE Input 时钟使能 CKE为高电平时 启动内部时钟信号 设备输入缓冲以及输出驱动单元
  • 函数、对象在内存中存在形式

    一 php底层内存分区 php将内存分为5个区 堆区一般存对象 栈区一般存基本数据类型 普通变量 和函数 全局区存全局变量和静态变量 常量区存常量 代码区存代码 二 函数调用时栈区变化 这是一个简单的递归函数示例 当主函数调用counts函
  • Linux mmap读/写触发共享文件页生命周期

    概述 Linux的mm内存子系统的核心功能就要要管理各种类型的page 确保能高效分配和释放 让物理内存得以最大化使用 初识内存系统往往关注的是page的申请和管理流程 容易忽略page的释放回收流程 其实理解mm中的内存回收和释放也是最核
  • spark用submit提交程序遇到的错误(机器内存较小)

    部署使用的spark版本是spark1 3 0部署环境 主节点centos7操作系统 2g内存 从节点debian系统1g内存 2个 spark env sh的设置如下 export SCALA HOME usr local scala 2
  • C++/QT 获取系统CPU、内存、磁盘、进程相关信息

    最近在学习用C 获取WINDOWS和LINUX 下的系统信息 对其大概方法做了一些总结 希望对新人有一些帮助 话不多说 先来代码 首先 我针对两个平台定义了一个接口类 即纯虚函数类 其windows 和 linux 的实现类可以实现该类 接
  • Linux mmap系统调用视角看缺页中断

    问题 1 mmap具体是怎么实现比read write少一次内存copy的 2 mmap共享映射和私有映射在内核实现的时候到底有什么区别 3 mmap的文件映射和匿名映射在内核实现的时候到底有什么区别 4 父子进程的COW具体怎么实现的 概
  • 内存管理<原理篇>(四、分段和分页)

    文章目录 4 1 分段 4 1 1 程序段介绍 4 1 2 各段放入内存信息 4 1 3 段表 4 1 4 总结 4 2 分页 4 2 1 概念介绍 4 2 2 各段加载进内存 4 2 3 例子分析 4 2 4 总结 4 1 分段 在上一篇
  • 反汇编笔记

    1 OD中ctrl f9 运行到返回 就是运行到当前断点所在的函数末尾 retn xxx 处 若xxx 10 那么 10等于10进制的16 就是说这个函数有4个参数 一个参数默认是占4字节 所以就是retn 10 2 调试程序时 在OD内部
  • linux 查询服务器的配置信息

    linux下看配置 可没有windows那么直观 你只能一个一个查看 一 cpu root srv more proc cpuinfo grep model name root srv grep model name proc cpuinf
  • malloc与free的底层实现

    1本节引言 内存管理内幕 Linux内存管理 Malloc 本文引用了下面这篇文章 读完下面 应该读下上面两篇文章 其中 内存管理内幕 提供了一个简单的malloc free实现版本 看看它的free设计 相信有足够的吸引力 gnu fre
  • 关于“system”: 找不到标识符 的问题

    关于 system 找不到标识符问题和 包括 排除 设置禁用了加载功能的问题 这个问题主要是使用system pause 时造成的 可以删除或者注释这个语句试试 解决办法 1 添加头文件stdlib h 2 添加iostream h 另外
  • 作用域和内存问题

    文章目录 一 基本类型和引用类型的值 基本类型和引用类型的区别 1 动态的属性 2 复制变量值 3 传递参数 4 监测类型 二 执行环境及作用域 1 延长作用域链 2 没有块级作用域 一 基本类型和引用类型的值 变量可能包括两种不同的数据类
  • 牛客字符串

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 提示 这里可以添加本文要记录的大概内容 例如 随着人工智能的不断发展 机器学习这门

随机推荐

  • zynq audio pcm DMA

    本篇接着上一篇 概述pcm调用DMA操作流程 接着ynq alsa说起 181 static int axi i2s probe struct platform device pdev 182 183 struct resource res
  • 浅谈【Stable-Diffusion WEBUI】(AI绘图)的基础和使用

    文章目录 零 AI绘图 一 简单介绍 1 1 Stable Diffusion 1 2 Stable Diffusion WEB UI 1 3 SD WebUI启动器和整合包 二 使用 2 1 启动 控制台 WEBUI 2 2 模型 2 2
  • How to change SSH port on Centos 6, 7, and 8.

    In this tutorial we will go through the steps on how to change the SSH port on Centos 6 7 and 8 Download PDF Posted 23 S
  • 解决vue白屏问题

    咱们先看看vue白屏在ios手机上是如何产生的 首页跳转到到第二屏 再从二级页面返回到首页就会出现白屏情况 解决思路 既然是首页白屏那么就要从首页开始解决问题 经过多次比对发现 返回到首页后 出现白屏 然后咱们用手触摸或则向下滑动 白屏就没
  • opencv编写均值滤波_opencv3.2.0图像处理之均值滤波blur API函数

    均值滤波 blur函数 函数原型 void blur InputArray src OutArray dst Size ksize Point anchor point int borderType BORDER DEFAULT 参数详解同
  • 仿叮咚买菜开源代码

    1 预览 1 前台 http dingdong nodebook top github地址 https github com cgq001 dingdong 2 后台管理 http dingdong admin nodebook top g
  • Python 中的列表推导式

    Python 中的列表推导式 简单用法 添加多个条件 多个列表使用 替换 Reduce 和 Lambda 嵌套列表推导式 列表推导式是一种 Python 构造 可减少生成新列表或过滤现有列表所需的代码行 列表推导式包含在方括号内 它由一个表
  • 12306查询车票信息返回的数据解析

    例如普通k 返回的车次信息 26000K772633 K7727 HDP QTP BXP TJP 00 42 02 33 01 51 Y UqBhHc2N4C1b00y5vYeRuG025cKMjh0sxUwHbuwDNWuOXRhule
  • shell case语句及函数

    case 菜单选择打印 语法 case var in var变量 patten 1 匹配模式1 a b c 和or类似 command 需要执行的命令 命令执行完毕 patten 2 command 默认值 没有匹配的模式 command
  • 【java】java中解决线程安全问题的三种方法

    java中解决线程安全问题的三种方法 当我们使用线程进行卖票时会出现诸多的安全问题为了解决这种情况 有三种方法可以进行选择 第一种是同步代码块 第二种是同步方法 第三种是Lock锁 在没有用的解决安全问题的时候会出现以下问题 测试类 pub
  • IIS7.0、7.5解析漏洞利用

    IIS7 0 7 5解析漏洞利用 1 测试漏洞是否可用 2 WebShell制作 3 上传WebShell 4 连接WebShell 1 测试漏洞是否可用 网站任意图片地址后加 脚本类型 若出现编译错误 则漏洞存在 2 WebShell制作
  • AI对游戏外包开发的影响

    人工智能 AI 对游戏行业产生了深远的影响 从游戏设计 开发到玩家体验等方面都发挥着重要作用 以下是AI对游戏行业的一些主要影响 和大家分享一些观点 希望对大家有所帮助 北京木奇移动技术有限公司 专业的软件外包开发公司 欢迎交流合作 1 游
  • 使用Vlc.DotNet打开摄像头并截图 C#

    参考上一篇 使用vlc打开usb摄像头 理论上输入下面地址 dshow dshow size 1600 1200 dshow vdev USB CAM2 C 就能打开摄像头了类似打开本地文件或者rtsp之类的网络地址 但实际测试怎么着都是打
  • 计算机网络复习4----TCP的拥塞窗口cwnd大小与传输轮次n的关系

    这里是 凤凰谷佛的计算机网络复习系列之4 一起来看看吧 书中P236 图5 27 1 5 39 TCP的拥塞窗口cwnd大小与传输轮次n的关系如下所示 试分析回答 1 指明TCP工作在慢开始阶段的时间间隔 解析 满开始时间间隔看在哪一刻2倍
  • traits:Traits技术初探

    概述 traits是一种特性萃取技术 color 663300 font family 宋体 padding 0px margin 0px gt 它在Generic Programming中被广泛运用 常常被用于使不同的类型可以用于相同的操
  • PHP文件包含漏洞代码分析-通过漏洞getshell-学习笔记

    一 原理分析 文件包含漏洞是代码注入的一种 其原理就是注入一段用户能控制的脚本或代码 并让服务器端执行 代码注入的典型代表就是文件包含 File inclusion 文件包含可能会出现在jsp php asp等语言中 服务器通过函数去包含任
  • Python笔记4

    迭代器 迭代是Python最强大的功能之一 是访问集合元素的一种方式 迭代器是一个可以记住遍历的位置的对象 迭代器对象从集合的第一个元素开始访问 直到所有的元素被访问完结束 迭代器只能往前不会后退 迭代器有两个基本的方法 iter 和 ne
  • css flex布局 —— 项目属性 align-self

    align self属性定义 flex 子项单独在侧轴 纵轴 方向上的对齐方式 可覆盖 align items 属性 默认值为 auto 表示继承父元素的 align items 属性 如果没有父元素 则等同于 stretch 语法 ite
  • 实战--Kafka入门(一)

    问题导读 1 如何理解消息队列 MessageQueue 2 如何解析Kafka基础架构 3 如何安装Kafka集群 4 Kafka命令行操作有哪些 第1章 Kafka概述1 1定义 Kafka是一个分布式的基于发布 订阅模式的消息队列 主
  • 关于野指针的一些问题与总结

    void Test void char str char malloc 100 strcpy str hello free str if str NULL strcpy str world printf str 请问运行Test函数会有什么