兰色精灵 发表于 2015-1-16 11:05:00

来谈谈:C 言语中的指针和内存泄露

要多google,因为我不可能,也不可以给你解答所有内容,我只能告诉你一些关键点,甚至我会故意隐瞒答案,因为在寻找答案的过程中。
  在利用C言语时,您是不是对花工夫调试指针和内存泄露成绩感应厌倦?假如是如许,那末本文就合适您。您将懂得大概招致内存损坏的指针操纵范例,您还将研讨一些场景,懂得要在利用静态内存分派时思索甚么成绩。
 弁言

  关于任何利用C言语的人,假如问他们C言语的最年夜懊恼是甚么,个中很多人大概会回覆说是指针和内存泄露。这些切实其实是损耗了开辟职员年夜多半调试工夫的事项。指针和内存泄露对某些开辟职员来讲仿佛使人害怕,可是一旦您懂得了指针及其联系关系内存操纵的基本,它们就是您在C言语中具有的最壮大工具。
  本文将与您分享开辟职员在入手下手利用指针来编程前应当晓得的奥密。本文内容包含:


[*]招致内存损坏的指针操纵范例
[*]在利用静态内存分派时必需思索的反省点
[*]招致内存泄露的场景
  假如您事后晓得甚么中央大概堕落,那末您就可以够当心制止圈套,并打消年夜多半与指针和内存相干的成绩。
  甚么中央大概堕落?

  有几种成绩场景大概会呈现,从而大概在完成天生后招致成绩。在处置指针时,您可使用本文中的信息来制止很多成绩。
 未初始化的内存

  在本例中,p已被分派了10个字节。这10个字节大概包括渣滓数据,如所示。
char*p=malloc(10);  .渣滓数据


  假如在对这个p赋值前,某个代码段实验会见它,则大概会取得渣滓值,您的程序大概具有不成展望的举动。p大概具有您的程序从不曾意料到的值。
  优秀的理论是一直分离利用memset和malloc,大概利用calloc。
char*p=malloc(10);memset(p,’’,10);  如今,即便统一个代码段实验在对p赋值前会见它,该代码段也能准确处置Null值(在幻想情形下应具有的值),然后将具有准确的举动。
 内存掩盖

  因为p已被分派了10个字节,假如某个代码片断实验向p写进一个11字节的值,则该操纵将在不告知您的情形下主动从其他某个地位“吃失落”一个字节。让我们假定指针q暗示该内存。
  .原始q内容


  .掩盖后的q内容


  了局,指针q将具有从未意料到的内容。即便您的模块编码得充足好,也大概因为某个共存模块实行某些内存操纵而具有不准确的举动。上面的示例代码片断也能够申明这类场景。
char*name=(char*)malloc(11);//Assignsomevaluetonamememcpy(p,name,11);//Problembeginshere  在本例中,memcpy操纵实验将11个字节写到p,尔后者仅被分派了10个字节。
  作为优秀的理论,每当向指针写进值时,都要确保对可用字节数和所写进的字节数举行交织查对。一样平常情形下,memcpy函数将是用于此目标的反省点。
 内存读取越界

  内存读取越界(overread)是指所读取的字节数多于它们应有的字节数。这个成绩其实不太严峻,在此就不再胪陈了。上面的代码供应了一个示例。
char*ptr=(char*)malloc(10);charname;memcpy(name,ptr,20);//Problembeginshere  在本例中,memcpy操纵实验从ptr读取20个字节,可是后者仅被分派了10个字节。这还会招致不但愿的输入。
 内存泄露

  内存泄露大概真正使人厌恶。上面的列表形貌了一些招致内存泄露的场景。


[*]从头赋值我将利用一个示例来讲明从头赋值成绩。
char*memoryArea=malloc(10);char*newArea=malloc(10);这向以下面的所示的内存地位赋值。
.内存地位

memoryArea和newArea分离被分派了10个字节,它们各自的内容如所示。假如或人实行以下所示的语句(指针从头赋值)……
memoryArea=newArea;则它一定会在该模块开辟的后续阶段给您带来贫苦。
在下面的代码语句中,开辟职员将memoryArea指针赋值给newArea指针。了局,memoryArea之前所指向的内存地位酿成了伶仃的,以下面的所示。它没法开释,由于没有指向该地位的援用。这会招致10个字节的内存泄露。
.内存泄露

在对指针赋值前,请确保内存地位不会变成伶仃的。

[*]起首开释父块假定有一个指针memoryArea,它指向一个10字节的内存地位。该内存地位的第三个字节又指向某个静态分派的10字节的内存地位,如所示。
.静态分派的内存

free(memoryArea)假如经由过程挪用free来开释了memoryArea,则newArea指针也会因而而变得有效。newArea之前所指向的内存地位没法开释,由于已没有指向该地位的指针。换句话说,newArea所指向的内存地位变成了伶仃的,从而招致了内存泄露。
每当开释布局化的元素,而该元素又包括指向静态分派的内存地位的指针时,应起首遍历子内存地位(在此例中为newArea),并从那边入手下手开释,然后再遍历回父节点。
这里的准确完成应当为:
free(memoryArea->newArea);free(memoryArea);
[*]前往值的不准确处置偶然,某些函数会前往对静态分派的内存的援用。跟踪该内存地位并准确地处置它就成了calling函数的职责。
char*func(){returnmalloc(20);//makesuretomemsetthislocationto‘’…}voidcallingFunc(){func();//Problemlieshere}在下面的示例中,callingFunc()函数中对func()函数的挪用未处置该内存地位的前往地点。了局,func()函数所分派的20个字节的块就丧失了,并招致了内存泄露。

 偿还您所取得的

  在开辟组件时,大概存在大批的静态内存分派。您大概会忘了跟踪一切指针(指向这些内存地位),而且某些内存段没有开释,还坚持分派给该程序。
  一直要跟踪一切内存分派,并在任何得当的时分开释它们。现实上,能够开辟某种机制来跟踪这些分派,好比在链表节点自己中保存一个计数器(但您还必需思索该机制的分外开支)。
 会见空指针

  会见空指针长短常伤害的,由于它大概使您的程序溃散。一直要确保您不是在会见空指针。
 总结

  本文会商了几种在利用静态内存分派时能够制止的圈套。要制止内存相干的成绩,优秀的理论是:


[*]一直分离利用memset和malloc,或一直利用calloc。
[*]每当向指针写进值时,都要确保对可用字节数和所写进的字节数举行交织查对。
[*]在对指针赋值前,要确保没有内存地位会变成伶仃的。
[*]每当开释布局化的元素(而该元素又包括指向静态分派的内存地位的指针)时,都应起首遍历子内存地位并从那边入手下手开释,然后再遍历回父节点。
[*]一直准确处置前往静态分派的内存援用的函数前往值。
[*]每一个malloc都要有一个对应的free。
[*]确保您不是在会见空指针。
安装和登录命令:login、shutdown、halt、reboot、mount、umount、chsh

只想知道 发表于 2015-1-18 07:46:50

经过这周的实训,我收获颇多,从中发现了自己的不足之处,也增长了很多见识。在此,要感谢我们的指导老师邹锋,感谢他一周以来的耐心教导。

因胸联盟 发表于 2015-1-25 08:47:49

我也学习了几天VB,然后不敢示弱得心把我拉回去,也不知道怎么回事,有一天灵感光顾,就这样,轻松进门,只用了一周。以后学习数据库编程,Socket编程也遇到类似得情况,

深爱那片海 发表于 2015-2-2 21:42:18

体会到C++语言具有的语句简洁,使用灵活,执行效率高等特点。发现上机实训的重要作用,特别是对数组和循环有了深刻的理解。

第二个灵魂 发表于 2015-2-8 07:19:17

算法这一块,理解泛型的思路,标准库里针对于容器的算法,接口都大致一样。

再见西城 发表于 2015-2-25 00:21:20

可以说是C++的核心,相对来说也比较难以理解,因为这些技术很多都是面向于写库的人,初学C++的人很难用得上。

若相依 发表于 2015-3-7 14:55:20

说起来,C++Primer和那本Plus思路不一样,这本书第3章就开始教你用标准库,用string对象与vector容器,所以对基础薄弱的同学来说上手有点难。

谁可相欹 发表于 2015-3-15 09:04:40

确实如此,你让一个使用惯C++的人看你在程序中夹杂些诸如 printf(),scanf(),这些原本就很简单的函数,实在有些过分,一个cout直接就很清晰的输出语句,被搞得又是变量类型,又是变量名称。

分手快乐 发表于 2015-3-22 00:33:36

体会到C++语言具有的语句简洁,使用灵活,执行效率高等特点。发现上机实训的重要作用,特别是对数组和循环有了深刻的理解。
页: [1]
查看完整版本: 来谈谈:C 言语中的指针和内存泄露