嵌入式软件开发------指针和内存释放的问题分析

2023-05-16

指针和内存的问题关于指针分配是否要delete的问题:
1.请大家在使用指针变量时遵守以下几点,可以让你们在编程时 
少许多的麻烦,以下假设p为某个类型的指针变量。 
(1)定义指针: 
   (a)定义指针变量时赋初值为type* p=NULL; 
      若是指针数组,刚用循环语句集体赋初值为NULL, 
      或调用api函数ZeroMemory(指针数组开始地址,0,数组大小(按字节算)); 
(2)使用指针: 
   (a)确定是否已经指向某个地址。 
      请用if(p!=NULL) 
             正常语句; 
          else 
            TRACE("p points to NULL"); 
      使用TRACE(..)函数对调试非常有用 
     
   (b)要确定指针变量所指向的变量的类型。 
      如在使用语句p++,p--时,更要如此,有时还要注意到 
      类型的强制转换,以及类型强制转换带来的后果。 
      同时,最好先用pOld=p保存起来
   (c)当动态申请内存时,如p=new 某个类型; 
      在这种用途时,一般来说p之前不会指向某个普通变量(视具体程序而不同), 
      所以可采用 
      if(p==NULL) 
      {
        p=new 某个类型; 
        if ( !p ) { … }      //在new以后立刻检查是否得到有效的空间 
      }
      else 
        出错处理;     
      若是p在new之前已经不等于0,则很可能是之前已经为p申请某些动态内存, 
      需要及时释放。 
      对应于这种情况,因此在释放p所指向的内存时, 
      建议使用 
      if(p!=NULL) 
      { 
          delete p;   //  (或delete []p;看情况了) 
          p=NULL;   // 请注意最好加上这一句。 delete操作只是释放p所指向的内存,
但是并不将
                   // p赋值为NULL。  
      } 
    (d)请最好不要将两个指针变量指向同一块动态内存, 
       因为其中一个释放了动态内存以后,虽然另一个指针 
       所指向的内存地址不等于NULL,但是因为内存已被释放, 
       所以若用这个指针时,则会出错。 
       如果需要将两个指针指向同一个动态内存的话, 
       则在编程时要特别小心。 
(3)释放指针所指向的动态内存时: 
     (a)上面已经讲到两种情况 
     (b)最好将类的成员变量中的指针全部赋值为NULL(有时则可以为NULL, 
        或肯定不能赋为NULL,如在成员变量是static类型时,视程序而定)。 
2.在类里面用到动态分配内存的指针,下面是规范的4部曲
(1) 构造函数中    m_pData=NULL;   (2)重复更新和分配   if (m_pData!=NULL)     
delete []m_pData;// or  delete m_pData;   m_pData=new .....   (3).所有使用指针的
地方   if(m_pData!=NULL)     {     }   else 
    TRACE("p points to NULL"); (4).析构函数   if(m_pData)      delete []m_pData;
    // or  delete m_pData; 
<说明一点>:类里面用到指针成员变量是很容易出错的一个地方;
我们把一个指针作为成员变量,在某个或者某些成员函数中,要多次给他分配内存,当然,
我们再分配之前必须保证它原先没有指向任何内存(否则就内存泄漏了)
如果判断呢,我想大部分人会这么写:
if (m_pData!=NULL)     delete []m_pData;// or  delete m_pData;   m_pData=new .
....   
就是用m_pdata是否为NULL来判断指针是否已经有内存,
那么如果我在别的地方将这块内存delete后没有把指针置为NULL,那么碰到
这样的判断语句会发生什么样的情况,想必大家都看到了。    
3.内存分配和释放的分工问题。   我觉得应该明确分配和释放的角色,一个指针只有唯一
一个对象分配,也有唯一一个对 象释放。 绝对应该避免多头分配释放问题。 COM中的内存
分配原则就是很好的例子 COM接口的参数,有三种方向类型[in],[out],[in,out] [in]指针
的内存,是在调用者分配空间调用者释放 [out]指针的内存,是被调用者分配,调用者释放
,且调用者不需要事先初始化 [in,out]指针内存,调用者必须初始化,被调用者可以根据
需要是否重新分配内存 最后由调用者进行清理。 不管哪种形式,一个地址的分配和释放总
是唯一的。 所以,在 FatMouse刚才的那个例子中 p到底是由子类维护还是父类维护呢? 
事实上,由于子类的析构函数自动调用父类的析勾函数 子类不需要对父类的指针进行释放
。 
4.动态分配内存后不释放是肯定会有内存泄漏的
  有一种说法是程序退出的时候编译器是会做内存回收的,我看了一下代码,发现退出main的
时候是会做一些清理工作,主要是把栈清除一下; 
运行的时候的调用栈是这样: 
main() 
maincrtstrartup() 
kernel32 
其中: 
mainCRTStartup: 
。。。。。。 
00421F30   mov         edx,dword ptr [__environ (0047c3dc)] 
00421F36   push        edx 
00421F37   mov         eax,[___argv (0047c3d4)] 
00421F3C   push        eax 
00421F3D   mov         ecx,dword ptr [___argc (0047c3d0)] 
00421F43   push        ecx 
00421F44   call        @ILT+550(_main) (0040122b) 
00421F49   add         esp,0Ch 
00421F4C   mov         dword ptr [mainret],eax 
00421F4F   mov         edx,dword ptr [mainret] 
00421F52   push        edx 
00421F53   call        exit (00426040) 
。。。。。 
先是向栈压入edx,随后压入命令行参数,在返回之前pop出命令行参数,edx,返回之后, 
把返回值保留在edx中,随后再次压入栈内,调用exit() 
并没有垃圾内存的回收(即delete那块new出来的内存/现在已经没有指针变量可以标示 
它了) 
之所以你没有delete而在退出程序后觉得好像没有内存泄漏我想是操作系统为你做了垃圾
collector的
工作,一个操作系统要是连这个都做不到  那他也太懒了
5.关于内存释放的时机
有一种习惯说是在退出程序的时候释放所有已经分配的内存,同时指针置为null,我认为到了
退出时再释放内存已经太晚了,而且没有任何意义(如上所见反正系统会帮你释放得),释放
内存应该在不再使用时就立刻释放。
常见的内存分配和使用错误
 
1) 内存的申请和分配并没有成功,但程序员却使用了它。一些新手经常会犯这种错误,他们并不会留意到内存没有分配成功。判断指针的值是否为NULL可以有效地避免这种错误。
2) 内存的分配已经成功,但是却没有进行初始化就直接使用它了。首先是观念上的问题,很多人都没有在使用指针前要初始化这样的习惯,然而这个习惯却是很重要的,希望大家一定要强迫自己养成。第二就是主观地认为自己申请的内存的缺省值为0,这样想是没有什么道理的,内存分配后的值是不确定的。
3) 上面的两种工作都已经做好了(已经成功申请并初始化完成),但是操作时却越界了。
4) 申请了内存,使用完了却忘记了释放,导致内存泄露。这样的错误可以形容为一个恶性的肿瘤,它不会马上要你的命,但是它会慢慢地吞噬你的系统资源,直到你的程序彻底完蛋。
5) 你很小心地释放了内存,但是却又使用了它。由于程序很复杂或者调用顺序出错,这样可能导致出现上面的错误。
 
指针---一把伟大的双刃剑
 
我真的非常佩服发明指针的人,他简直太伟大了。能使用如此简洁地方法将复杂的内存结构描述的如此清楚,这本身就是一种伟大的成就。但是,指针之于程序员如同武器之于士兵,用好了可以威力无比,用不好则害人害己。
我先说说指针和数组的区别。数组名对应着一块内存,它的地址、容量在其生命周期中是不可变的,只有数组内容是可变的。指针可随时指向任何类型的内存,它的特点就是“变”。指针远比数组灵活,但也更危险。
数组名是不能直接进行赋值和比较的。如果你向要将数组a赋值给数组b,不能直接用赋值语句b = a ,这样会令编译器产生错误的。必须使用标准的库函数strcpy来进行赋值。相同地,要比较a和b的内容是否相同,不能使用普通的逻辑判断if(b==a),也要应用库函数strcmp来判断。
//数组……
char a[] = “hello”;
char b[100];
strcpy(b, a); // b = a is wrong
if (strcmp(b, a) == 0) //if (b == a) is wrong
cout<<b<<endl;
//指针……
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len+1));
strcpy(p, a);
if (strcmp(p, a) == 0)
cout<<p<<endl;
free(p);
在计算内存容量的时候有一点是必须要指出的,那就是sizeof计算数组是计算它的实际的内存容量,而计算指针时则永远都是4个字节。C++是永远没有办法知道指针所指的内存容量,除非在申请时记住它。
 
free和delete如何对付指针?
 
程序员都知道它们是用来释放申请的内存的,但是却很少有人注意到指针本身并没有发生什么变化。各位可以在VC中使用单步跟踪一下,你们会惊奇地发现当指针p被调用了free后它的地址值并没有改变,只是该地址对应的内存中原来有意义的值变成了垃圾,“p”却还是指向的这块内存。记住,一定要第一时间将p的值设为NULL,否则会让别人以为p是一个有意义的指针而误使用它(当别人使用该指针时会判断指针的值是否为NULL,如果不为NULL就会以为它有意义)。
也就是说调用了free(p)之后,p仍然指向那块内存,假若不显示设置为NULL的话,以后就不能使用if (NULL == p)来判断p是否释放
char *p = (char *)malloc(100);
strcpy(p, “hello”);
free(p); // the address of “p” is not changed.
….
if (NULL != p) //it will return TRUE
strcpy(p, “world”); //Wrong!!!
下面提两点,让大家可以防止上面的情况出现:
1) 指针声明后要马上初始化。因为指针出现的缺省值是随机的,所以一定要赋值为NULL,然后再使用。
2) 调用了free和delete后一定要将指针赋值为NULL。原因上面已经提过了,就不再赘述了。
C++父类子类指针函数调用注意事项(虚拟函数与多型Polymorphism)
1,如果以一个基础类指针指向一个衍生类对象,那么经由该指针只能访问基础类定义的函数
2,如果以一个衍生类指针指向一个基础类对象,必须先做强制转型动作(explicit cast),这种做法很危险,也不符合生活习惯,在程序设计上也会给程序员带来困扰。
3,如果基础类和衍生类定义了相同名称的成员函数,那么通过对象指针调用成员函数时,到底调用那个函数要根据指针的原型来确定,而不是根据指针实际指向的对象类型确定。
 
虚拟函数就是为了对“如果你以一个基础类指针指向一个衍生类对象,那么通过该指针,你只能访问基础类定义的成员函数”这条规则反其道而行之的设计。
 
如果你预期衍生类由可能重新定义一个成员函数,那么你就把它定义成虚拟函数( virtual )。
 
polymorphism就是让处理基础类别对象的程序代码能够通透的继续适当地处理衍生类对象。
 
纯虚拟函数:
virtual void myfunc ( ) =0;
纯虚拟函数不许定义其具体动作,它的存在只是为了在衍生类钟被重新定义。只要是拥有纯虚拟函数的类,就是抽象类,它们是不能够被实例化的。如果一个继承类没有改写父类中的纯虚函数,那么他也是抽象类,也不能被实例化。
 
抽象类不能被实例化,不过我们可以拥有指向抽象类的指针,以便于操纵各个衍生类。
 
虚拟函数衍生下去仍然是虚拟函数,而且还可以省略掉关键字“virtual”。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

嵌入式软件开发------指针和内存释放的问题分析 的相关文章

  • 小学数学公式大全

    小学数学公式大全 第一部分 xff1a 概念 1 加法交换律 xff1a 两数相加交换加数的位置 xff0c 和不变 2 加法结合律 xff1a 三个数相加 xff0c 先把前两个数相加 xff0c 或先把后两个数相加 xff0c 再同第三
  • c++中的点号(.),冒号(:)和双冒号(::)运算符

    1 冒号 xff08 xff09 用法 xff08 1 xff09 表示机构内位域的定义 xff08 即该变量占几个bit空间 xff09 typedef struct XXX unsigned char a 4 char型的字符a占4位
  • C++ 对象和实例的区别,以及用new和不用new创建类对象区别

    起初刚学C 43 43 时 xff0c 很不习惯用new xff0c 后来看老外的程序 xff0c 发现几乎都是使用new xff0c 想一想区别也不是太大 xff0c 但是在大一点的项目设计中 xff0c 有时候不使用new的确会带来很多
  • 巫泽俊...《挑战程序设计竞赛》算法及相关书籍论点

    为什么要参加程序设计竞赛 能提高程序设计能力 xff0c 掌握技巧 减少错误 xff1b 能结识更多的同好 xff0c 交流切磋 xff1b 能更好地推销自己 xff08 大赛的前几名往往受到世界知名公司的青睐 xff09 秋叶拓哉认为 x
  • (struct)结构体变量作为函数参数调用的方法小结

    结构体变量 结构指针变量 结构数组作为函数的参数应用实例分析 struct stud long int num float score 结构体变量作为函数的参数 xff0c 修改之后的成员值不能返回到主调函数 void funvr stru
  • 搭建nginx反向代理用做内网域名转发

    基于域名的7层转发的实现 xff08 NAT 43 反向代理 xff09 在实际办公网中 xff0c 因为出口IP只有一个 xff0c 要实现对外提供服务的话就必须得做端口映射 xff0c 如果有多个服务要对外开放的话 xff0c 这只能通
  • 从平面上最近的点对,谈谈分治算法

    首先介绍一下分治 xff08 Divide and Conquer xff09 算法 xff1a 设计过程分为三个阶段 Divide xff1a 整个问题划分为多个子问题 Conquer xff1a 求解各子问题 递归调用正设计的算法 Co
  • NOIP2017 国庆郑州集训知识梳理汇总

    第一天 基础算法及数学 基本算法 递推 递归 分治 二分 倍增 贪心 递推 指通过观察 归纳 xff0c 发现较大规模问题和较小规模问题之间的关系 xff0c 用一些数学公式表达出来 在一些题解中 xff0c 和 计数DP 是指同一个概念
  • 挑战程序设计竞赛 — 知识总结

    准备篇 1 5 运行时间 概述编写的目的是面向ACM程序设计竞赛 xff0c 不可避免的要涉及复杂度和运行时间的问题 xff0c 本节给出了解决问题算法选择的依据 假设题目描述中给出的限制条件为n lt 61 1000 xff0c 针对O
  • 阿里巴巴笔试题选解

    阿里巴巴笔试题选解 9月22日 xff0c 阿里巴巴北邮站 小题 xff1a 1 有三个结点 xff0c 可以构成多少种二叉树形结构 xff1f 2 一副牌52 张 去掉大小王 xff0c 从中抽取两张牌 xff0c 一红一黑的概率是多少
  • 腾讯2014软件开发笔试题目

    腾讯2014软件开发笔试题目 9月21日 xff0c 腾讯2014软件开发校招 简答题 广州 简答题 xff1a 1 请设计一个排队系统 xff0c 能够让每个进入队伍的用户都能看到自己在 中所处的位置和变化 队伍可能随时有人加入和退出 x
  • MAVLink简介

    MAVLink简介 Mavlink协议最早由 苏黎世联邦理工学院 计算机视觉与几何实验组 的 Lorenz Meier于2009年发布 xff0c 并遵循LGPL开源协议 Mavlink协议是在串口通讯基础上的一种更高层的开源通讯协议 xf
  • C/C++ 服务器程序(从入门到精通)

    Windows 服务被设计用于需要在后台运行的应用程序以及实现没有用户交互的任务 为了学习这种控制台应用程序的基础知识 xff0c C xff08 不是C 43 43 xff09 是最佳选择 本文将建立并实现一个简单的服务程序 xff0c
  • 图像处理常用算法(C++/OPENCV)

    添加椒盐噪声 void salt Mat amp src int number for int i 61 0 i lt number i 43 43 int r 61 static cast lt int gt rng uniform 0
  • 【解决linux下连接向日葵失败或连接之后断开的解决方案】

    解决linux下连接向日葵失败或连接之后断开的解决方案 linux在软件中搜索lightdm桌面管理器并安装即可 xff01
  • 机器学习推荐系统评价指标之AUC

    机器学习推荐系统评价指标之AUC 综述AUC的计算过程AUC的优势 综述 AUC是机器学习模型中常见评价指标 xff0c 在推荐系统中也十分常见 和常见的评价指标Acc xff0c P xff0c R相比 xff0c AUC具备一定的优势
  • 多线程访问同步方法情况

    文章目录 1 多线程访问同步方法1 1 两个线程同时访问一个对象的同步方法1 1 1 代码演示1 1 2 运行结果 1 2 两个线程访问的是两个对象的同步方法1 2 1 代码演示1 2 2 运行结果 1 3 两个线程访问的是synchron
  • 剑指 Offer 33. 二叉搜索树的后序遍历序列

    题目描述 xff1a 输入一个整数数组 xff0c 判断该数组是不是某二叉搜索树的后序遍历结果 如果是则返回 true xff0c 否则返回 false 假设输入的数组的任意两个数字都互不相同 参考以下这颗二叉搜索树 xff1a 5 2 6
  • 求解空间两个三维坐标系之间的变换矩阵

    三维刚体变换模型 即旋转 平移矩阵 RT矩阵 的估计方法 原理简单阐述 只要算出变换矩阵 就可以算出A坐标系的一个点P在坐标系B里的对应点坐标 即 T为3x3的转换矩阵 t 为3x1的位移变换向量 这里点坐标均为3x1的列向量 非齐次形式
  • Ubuntu下网络调试助手 NetAssist

    近期在ubuntu下开发一个网络相关的程序 之前在windows上开发时 xff0c 一直使用NetAssist这个小工具 xff0c 简洁实用 所以就安装了一个对应版本的网络调试助手 NetAssist 下载地址 xff1a 链接 xff

随机推荐

  • 程序员裸辞三个月,终于拿到大厂offer!网友:不应该!

    一个行业发展成熟 xff0c 必定会重新洗牌 xff0c 就像朝代的更替一样 xff0c 现在互联网发展就是遇到了这样的瓶颈期 xff0c 出现了衰退 xff0c 就形成大家口中所说的 互联网寒冬 但是有技术的人哪里怕过寒冬 xff0c 所
  • HttpUtils 用于进行网络请求的工具类

    用于进行网络请求的工具类 xff0c 可进行get xff0c post两种请求 xff0c 值得一提的是这个utils给大家提供了一个回调接口 xff0c 方便获取下载文件的进度 span class hljs keyword impor
  • deepin系统

    https www uc23 net xinwen 76259 html 据介绍 xff0c 深度操作系统 xff08 deepin xff09 自 2015 年开始 xff0c 就放弃基于 Ubuntu 作为上游 xff0c 选择 Ubu
  • 学习日志2

    这几天一直在思考如何解决摄像头与vins与fast planner如何相结合再应用的问题 因为摄像头是因特尔的D435i xff0c 于是决定在gazebo上实现D435i的仿真 由于D435I版本较新 xff0c 因此github上基本没
  • 学习日志3

    这几天准备用分别用ego planner与fast planner进行飞行仿真 本来准备在双系统的ubuntu上安装ego planner xff08 之前ubuntu上已经安装过vins fusion vins mono与fast pla
  • 学习日志5

    最近老师让我阅读了一篇新文章 xff0c 文章标题如下图 文章通过解决时间分配问题以及通过模型预测轮廓同时控制问题控制 xff08 MPCC xff09 优化能够使四旋翼无人机找到最优轨迹 xff0c 可以快速地避障 xff0c 速度甚至可
  • 万字长文 | 阿里大佬 ssp offer 的后台服务器开发学习路线

    前言 小北去年经历春秋招 xff0c 拿到了不少大厂 offer xff0c 其中包括 sp ssp 等 xff0c 感觉在复习准备校招上还是有一定方法的 xff0c 因为我自己是 Linux C C 43 43 路线 所以这一篇的主题是
  • 看完谷歌大佬的刷题笔记, 我直接手撕了200道 Leetcode 算法题

    如果你刷leetcode觉得吃力 那么一定需要这份谷歌大佬的leetcode刷题笔记 在这里推荐一个谷歌大佬的刷题笔记 每一道题的题解都写得非常清楚 作者在美国卡内基梅隆大学攻读硕士学位时 xff0c 为了准备实习秋招 xff0c 他从夏天
  • JVM中的栈区域

    一 栈 xff1a 在JVM中也叫栈内存 xff0c 主要负责java程序的运行 xff0c 栈在线程创建时被创建 xff0c 栈时线程私有的 xff0c 也即每一个线程都有自己的栈空间 xff0c 线程之间的运行不受影响 相互独立 二 栈
  • 初步认识ADRC(自抗扰控制)与应用

    这是一个目录 ADRC的基本原理一 参考资料推荐二 为什么PID好 xff0c 以及 xff0c 为什么PID不够好1 为什么PID好 不依赖于模型的控制器2 为什么PID不够好 PID的缺点 三 ADRC给出的方案 如何保留PID的优点
  • 先进非线性控制方法 INDI 快速部署到PX4用于四旋翼控制(part2)

    目录 一 PX4 v11 的姿态控制解析1 角度环控制2 角速度环控制3 控制分配 二 简易INDI如何部署到PX41 获取角加速度 和 电机转速测量值 xff08 1 xff09 角加速度 xff08 2 xff09 转速 2 具体实现过
  • ubuntu18.04 cv2.VideoCapture无法读取视频

    源代码 xff1a span class token comment 读取视频 span span class token keyword import span cv2 video file span class token operat
  • 关于字符串结束标志‘\0‘的一些见解

    前言 本人是一个刚刚上路的IT新兵 菜鸟 分享一点自己的见解 如果有错误的地方欢迎各位大佬莅临指导 如果这篇文章可以帮助到你 劳请大家点赞转发支持一下 一 39 0 是什么 xff1f 0 是转义字符 xff0c 为了告诉编译器 0 是空字
  • gRPC 基础(二)-- Go 语言版 gRPC-Go

    gRPC Go Github gRPC的Go实现 一个高性能 开源 通用的RPC框架 xff0c 将移动和HTTP 2放在首位 有关更多信息 xff0c 请参阅Go gRPC文档 xff0c 或直接进入快速入门 一 快速入门 本指南通过一个
  • 校验和算法

    原文链接 xff1a http blog chinaunix net uid 26758209 id 3146230 html 校验和算法 经常看计算机网络相关的书时 xff0c 每次看到关于IP或者是UDP报头校验和时 xff0c 都是一
  • PID控制输出PWM核心代码(基于STM32F103)

    注 xff1a 1 如果对于PID控制原理不是很了解 xff0c 可以找些资料看 xff0c 最好先搞懂原理 2 程序中Kp Ki Kd 199 0可根据实际情况自己修改 全局变量 float target 61 30 0 目标温度 flo
  • (已修正精度 1mm左右)Realsense d435i深度相机+Aruco+棋盘格+OpenCV手眼标定全过程记录

    文章目录 2023 5更新 下面为原文 一 前期准备1 1 手眼标定原理1 2 Aruco返回位姿的原理1 3 生成一个Aruco Marker1 4 安装aruco ros包1 5 安装realsense ros包 二 实验环境三 实验过
  • 外贸常用英语词汇

    外贸常用英语词汇 国际贸易 出口信贷 export credit 出口津贴 export subsidy 商品倾销 dumping 外汇倾销 exchange dumping 优惠关税 special preferences 保税仓库 bo
  • Betaflight连接飞控相关问题

    问题描述 xff1a Betaflight连接飞控时 xff0c 若遇到 打开串口失败 xff0c 则为飞控芯片驱动未安装的原因 xff0c 此时 xff0c 在设备管理器中是看不到所连接的硬件的 解决方法 xff1a Betaflight
  • 嵌入式软件开发------指针和内存释放的问题分析

    指针和内存的问题关于指针分配是否要delete的问题 1 请大家在使用指针变量时遵守以下几点 xff0c 可以让你们在编程时 少许多的麻烦 xff0c 以下假设p为某个类型的指针变量 1 定义指针 xff1a a 定义指针变量时赋初值为ty