我们从2011年坚守至今,只想做存粹的技术论坛。  由于网站在外面,点击附件后要很长世间才弹出下载,请耐心等待,勿重复点击不要用Edge和IE浏览器下载,否则提示不安全下载不了

 找回密码
 立即注册
搜索
查看: 2828|回复: 21

[技术文章] C语言中的指针和内存泄漏

[复制链接]
  • TA的每日心情

    昨天 18:16
  • 签到天数: 99 天

    [LV.6]常住居民II

    3万

    主题

    8253

    回帖

    8万

    积分

    三级逆天

    积分
    81480

    终身成就奖特殊贡献奖原创先锋奖金点子奖优秀斑竹奖宣传大使奖

    发表于 2018-6-16 09:57:46 | 显示全部楼层 |阅读模式

    马上注册,结交更多好友,享用更多功能,让你轻松玩转社区

    您需要 登录 才可以下载或查看,没有账号?立即注册

    ×
    对于任何使用 C 语言的人,如果问他们 C 语言的最大烦恼是什么,其中许多人可能会回答说是指针和内存泄漏。这些的确是消耗了开发人员大多数调试时间的事项。指针和内存泄漏对某些开发人员来说似乎令人畏惧,但是一旦您了解了指针及其关联内存操作的基础,它们就是您在 C 语言中拥有的最强大工具。

                                   
    登录/注册后可看大图

    本文将与您分享开发人员在开始使用指针来编程前应该知道的秘密。本文内容包括:
    ●导致内存破坏的指针操作类型
    ●在使用动态内存分配时必须考虑的检查点
    ●导致内存泄漏的场景
    如果您预先知道什么地方可能出错,那么您就能够小心避免陷阱,并消除大多数与指针和内存相关的问题。
    什么地方可能出错?
    有几种问题场景可能会出现,从而可能在完成生成后导致问题。在处理指针时,您可以使用本文中的信息来避免许多问题。
    未初始化的内存
    在本例中,p已被分配了 10 个字节。这 10 个字节可能包含垃圾数据,如图 1所示。
    [blockquote]  char *p = malloc ( 10 );[/blockquote]图1.垃圾数据
    如果在对这个p赋值前,某个代码段尝试访问它,则可能会获得垃圾值,您的程序可能具有不可预测的行为。p可能具有您的程序从未曾预料到的值。
    良好的实践是始终结合使用memset和malloc,或者使用calloc。
    [blockquote]  char *p = malloc (10);
      memset(p,’’,10);
    [/blockquote]现在,即使同一个代码段尝试在对p赋值前访问它,该代码段也能正确处理Null值(在理想情况下应具有的值),然后将具有正确的行为。
    内存覆盖
    由于p已被分配了 10 个字节,如果某个代码片段尝试向p写入一个 11 字节的值,则该操作将在不告诉您的情况下自动从其他某个位置“吃掉”一个字节。让我们假设指针q表示该内存。
    图2.原始 q 内容
    图3.覆盖后的 q 内容
    结果,指针q将具有从未预料到的内容。即使您的模块编码得足够好,也可能由于某个共存模块执行某些内存操作而具有不正确的行为。下面的示例代码片段也可以说明这种场景。
    [blockquote]  char *name = (char *) malloc(11);
      // Assign some value to name
      memcpy ( p,name,11); // Problem begins here
    [/blockquote]在本例中,memcpy操作尝试将 11 个字节写到p,而后者仅被分配了 10 个字节。
    作为良好的实践,每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。一般情况下,memcpy函数将是用于此目的的检查点。
    内存读取越界
    内存读取越界 (overread) 是指所读取的字节数多于它们应有的字节数。这个问题并不太严重,在此就不再详述了。下面的代码提供了一个示例。
    [blockquote]  char *ptr = (char *)malloc(10);
      char name[20] ;
      memcpy ( name,ptr,20); // Problem begins here
    [/blockquote]在本例中,memcpy操作尝试从ptr读取 20 个字节,但是后者仅被分配了 10 个字节。这还会导致不希望的输出。
    内存泄漏
    内存泄漏可能真正令人讨厌。下面的列表描述了一些导致内存泄漏的场景。
    ●重新赋值我将使用一个示例来说明重新赋值问题。
    [blockquote]  char *memoryArea = malloc(10);
      char *newArea = malloc(10);
    [/blockquote]这向如下面的图 4所示的内存位置赋值。
    图4.内存位置

                                   
    登录/注册后可看大图
    memoryArea和newArea分别被分配了 10 个字节,它们各自的内容如图 4所示。如果某人执行如下所示的语句(指针重新赋值)……
    [blockquote]  memoryArea = newArea;[/blockquote]则它肯定会在该模块开发的后续阶段给您带来麻烦。
    在上面的代码语句中,开发人员将memoryArea指针赋值给newArea指针。结果,memoryArea以前所指向的内存位置变成了孤立的,如下面的图 5所示。它无法释放,因为没有指向该位置的引用。这会导致 10 个字节的内存泄漏。
    图5.内存泄漏

                                   
    登录/注册后可看大图
    ●在对指针赋值前,请确保内存位置不会变为孤立的。
    ●首先释放父块假设有一个指针memoryArea,它指向一个 10 字节的内存位置。该内存位置的第三个字节又指向某个动态分配的 10 字节的内存位置,如图 6所示。
    图6.动态分配的内存

                                   
    登录/注册后可看大图
    [blockquote]  free(memoryArea)[/blockquote]如果通过调用 free 来释放了memoryArea,则newArea指针也会因此而变得无效。newArea以前所指向的内存位置无法释放,因为已经没有指向该位置的指针。换句话说,newArea所指向的内存位置变为了孤立的,从而导致了内存泄漏。
    每当释放结构化的元素,而该元素又包含指向动态分配的内存位置的指针时,应首先遍历子内存位置(在此例中为newArea),并从那里开始释放,然后再遍历回父节点。
    这里的正确实现应该为:
    [blockquote]  free( memoryArea->newArea);
      free(memoryArea);
    [/blockquote]返回值的不正确处理
    有时,某些函数会返回对动态分配的内存的引用。跟踪该内存位置并正确地处理它就成为了calling函数的职责。
    [blockquote]  char *func ( )
      {
      return malloc(20); // make sure to memset this location to ‘’…
      }
      void callingFunc ( )
      {
      func ( ); // Problem lies here
      }
    [/blockquote]在上面的示例中,callingFunc()函数中对func()函数的调用未处理该内存位置的返回地址。结果,func()函数所分配的 20 个字节的块就丢失了,并导致了内存泄漏。
    归还您所获得的
    在开发组件时,可能存在大量的动态内存分配。您可能会忘了跟踪所有指针(指向这些内存位置),并且某些内存段没有释放,还保持分配给该程序。
    始终要跟踪所有内存分配,并在任何适当的时候释放它们。事实上,可以开发某种机制来跟踪这些分配,比如在链表节点本身中保留一个计数器(但您还必须考虑该机制的额外开销)。
    访问空指针
    访问空指针是非常危险的,因为它可能使您的程序崩溃。始终要确保您不是在访问空指针。
    总结
    本文讨论了几种在使用动态内存分配时可以避免的陷阱。要避免内存相关的问题,良好的实践是:
    ●始终结合使用memset和 malloc,或始终使用calloc。
    ●每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。
    ●在对指针赋值前,要确保没有内存位置会变为孤立的。
    ●每当释放结构化的元素(而该元素又包含指向动态分配的内存位置的指针)时,都应首先遍历子内存位置并从那里开始释放,然后再遍历回父节点。
    ●始终正确处理返回动态分配的内存引用的函数返回值。
    ●每个malloc都要有一个对应的 free。
    ●确保您不是在访问空指针。
    回复

    使用道具 举报

    该用户从未签到

    1

    主题

    6750

    回帖

    1285

    积分

    二级逆天

    积分
    1285

    终身成就奖特殊贡献奖原创先锋奖优秀斑竹奖

    发表于 2018-6-16 10:15:09 | 显示全部楼层
    回复

    使用道具 举报

    该用户从未签到

    466

    主题

    2040

    回帖

    8396

    积分

    二级逆天

    积分
    8396

    终身成就奖原创先锋奖特殊贡献奖优秀斑竹奖金点子奖

    QQ
    发表于 2018-6-16 12:19:34 | 显示全部楼层
    回复

    使用道具 举报

  • TA的每日心情
    擦汗
    2024-11-13 11:08
  • 签到天数: 2 天

    [LV.1]初来乍到

    12

    主题

    1388

    回帖

    2176

    积分

    1元学习Allegro(2期)旁听

    积分
    2176

    终身成就奖

    发表于 2018-6-16 13:54:41 | 显示全部楼层
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-11-5 11:22
  • 签到天数: 1 天

    [LV.1]初来乍到

    143

    主题

    4434

    回帖

    4162

    积分

    二级逆天

    积分
    4162

    终身成就奖社区居民忠实会员社区劳模最爱沙发原创达人优秀斑竹奖

    QQ
    发表于 2018-6-16 15:53:16 | 显示全部楼层
    回复

    使用道具 举报

    该用户从未签到

    635

    主题

    6403

    回帖

    1万

    积分

    三级逆天

    -

    积分
    13163

    忠实会员社区居民社区劳模原创达人最爱沙发终身成就奖特殊贡献奖原创先锋奖优秀斑竹奖金点子奖

    QQ
    发表于 2018-6-16 18:53:22 | 显示全部楼层
    -
    回复

    使用道具 举报

  • TA的每日心情
    开心
    前天 08:31
  • 签到天数: 145 天

    [LV.7]常住居民III

    7

    主题

    2495

    回帖

    2313

    积分

    二级逆天

    积分
    2313

    终身成就奖优秀斑竹奖特殊贡献奖

    QQ
    发表于 2018-6-16 21:07:04 | 显示全部楼层
    回复

    使用道具 举报

    该用户从未签到

    3

    主题

    151

    回帖

    511

    积分

    二级逆天

    积分
    511

    终身成就奖

    QQ
    发表于 2018-6-16 23:28:09 | 显示全部楼层
    回复

    使用道具 举报

    该用户从未签到

    0

    主题

    1822

    回帖

    2239

    积分

    二级逆天

    积分
    2239

    终身成就奖

    QQ
    发表于 2018-6-17 10:57:48 | 显示全部楼层
    回复

    使用道具 举报

  • TA的每日心情
    郁闷
    2024-12-14 17:04
  • 签到天数: 1 天

    [LV.1]初来乍到

    1

    主题

    1160

    回帖

    1193

    积分

    二级逆天

    积分
    1193

    终身成就奖

    QQ
    发表于 2018-8-26 08:32:18 | 显示全部楼层
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    每日签到,有金币领取。


    Copyright ©2011-2024 NTpcb.com All Right Reserved.  Powered by Discuz! (NTpcb)

    本站信息均由会员发表,不代表NTpcb立场,如侵犯了您的权利请发帖投诉

    ( 闽ICP备2024076463号-1 ) 论坛技术支持QQ群171867948 ,论坛问题,充值问题请联系QQ1308068381

    平平安安
    TOP
    快速回复 返回顶部 返回列表