C++ 内存管理,c++内存控制

  C++ 内存管理,c++内存控制

  C/c内存管理贴于2012-06-04 01:52 Sherwin _ Reading(1461)评论(6)编辑合集这是我第一次学习编程时整理的总结,主要来自一本叫《高质量c/c++编程》的书。很多年过去了,请再复习一遍。

  1、malloc()

  Malloc()函数用于分配内存:需要的总字节数作为参数传递给这个函数,返回值是指向新分配内存的指针,如果内存分配不好,返回值为NULL。

  malloc()的使用技术:

  some _ type *指针;

  指针=malloc(count * sizeof(* pointer));

  注意:

  (1)这个方法保证malloc()将分配正确的内存量,而不管指针的寿命。如果指针的类型后来改变了,sizeof操作符会自动确保要分配的字节数仍然是正确的。

  (2)2)malloc()返回的内存“未初始化”。这个内存可能包含任何随机垃圾。您可以立即用有效数据或至少零来初始化该内存。要用0初始化,可以使用

  void*memset(void*s,intc,size _ TN);

  (3)3)malloc()通过缺页异常最终获取的物理内存中的原始数据大多数情况下是0(但不能保证是0)。

  2、calloc()

  calloc()函数是malloc的一个简单包装器。它的主要优点是将动态分配的内存清零。

  void * calloc(size _ TN member,size _ tsize);

  有经验的程序员更喜欢用calloc(),因为这样新分配的内存就不会有问题。调用calloc()一定会清除0,避免调用memset()。

  3、realloc()

  原型:extern void * realloc(void * mem _ address,unsigned newsize);#include stdlib.h有些编译器需要# includealloc.h .将mem_address指向的内存区域大小改为newsize长度。如果重新分配成功,则返回指向已分配内存的指针,否则返回空指针NULL。当不再使用内存时,应该使用free()函数来释放内存块。

  注意:此处原始内存中的数据保持不变。

  4.malloc()和calloc()

  malloc()和calloc()函数都可以用来动态分配内存空间,但它们略有不同:

  (a)a)malloc()函数有一个参数,它是要分配的存储空间的大小:

  void * malloc(size _ tsize);

  calloc()函数有两个参数,即元素的数量和每个元素的大小。这两个参数的乘积就是要分配的内存空间的大小。

  void*calloc(size_tnumElements,size _ tsizeOfElement);

  (b)如果调用成功,函数malloc()和函数calloc()都将返回分配的内存空间的第一个地址。

  (c)malloc()和calloc()的主要区别是前者不能初始化分配的内存空间,而后者可以。

  (d)如果malloc()函数分配的内存空间以前从未被使用过,那么其中的每一位都可能是0;相反,如果这部分内存已经被分配,可能会有各种数据留在里面。也就是说,使用malloc()函数的程序,刚开始可以正常工作(内存空间没有被重新分配),但是过了一段时间(内存空间被重新分配),就可能出现问题。

  (calloc()函数会将分配的内存空间中的每一位初始化为零,也就是说,如果你为字符型或整型的元素分配内存,那么这些元素将保证被初始化为零;如果为指针类型的元素分配内存,这些元素通常被初始化为空指针;如果为实际数据分配内存,这些元素将被初始化为浮点零。

  (f)calloc(m,n)本质上等价于

  p=malloc(m * n);

  memset(p,0,m * n);

  5、自由和删除

  (a)它们只是释放指针所指向的内存,但并没有杀死指针本身。

  (b)P被释放后,其地址保持不变(非空),只是这个地址对应的内存是垃圾,P就变成了“野指针”。如果此时p没有设置为NULL,人们会误以为p是合法的指针。

  (c)有时候我们不记得P所指的内存是否已经释放。在继续使用P之前,我们通常使用if(p!=NULL)进行防错处理。但仅当p=NULL if(p!=NULL)才能工作。

  6.new和malloc

  (1)、new是C中的运算符,malloc是C中的函数.

  (2) new不仅会分配内存,还会调用类的构造函数。同样,delete会调用类的析构函数,而malloc只会分配内存,不会初始化类成员。同样,free也不会调用析构函数。

  (3)内存泄漏可以针对malloc或者new进行检查,不同的是new可以指示那个文件的行,但是malloc没有这个信息。

  (new与malloc的效率比较

  (a)new可以认为是malloc加上构造函数的执行。

  (b)b)new出来的指针是直接带类型信息的,而malloc返回的所有指针都是void指针。

  7.新建/删除和分配/自由

  (a)New/delete是运算符,malloc/free是函数。

  (b)malloc和free是C /C语言的标准库函数,new/delete是C的运算符,可以用来申请动态内存和释放内存。

  (c)对于非内部数据类型的对象,单靠maloc/free无法满足动态对象的要求。构造函数在对象创建时自动执行,析构函数在对象消亡前自动执行。由于malloc/free是库函数而不是操作符,不在编译器的控制范围内,所以执行构造函数和析构函数的任务不能强加给malloc/free。

  (d)不要试图用malloc/free来完成动态对象的内存管理,要用new/delete。Malloc/free和new/delete相当于内部数据类型的“对象”,因为它们没有构造和销毁的过程。

  (e)C语言需要一个可以完成动态内存分配和初始化的操作符new和一个可以完成内存清理和释放的操作符delete。注意,new/delete不是库函数。

  (f)newdelete在实现中实际调用malloc,free函数。除了分配内存,newoperator调用构造函数,malloc函数只负责分配内存。

  (g)既然new/delete的函数完全覆盖了malloc/free,为什么C不消除malloc/free?这是因为C程序经常调用C函数,而C程序只能用malloc/free管理动态内存。如果“new创建的动态对象”是免费发布的,对象无法执行析构函数,可能会导致程序错误。如果用delete来释放“malloc应用的动态内存”,理论上程序不会出错,但是程序的可读性很差。所以new/delete必须成对使用,malloc/free也一样。

  8.使用malloc/free积分

  (a)malloc只关心两个元素:“类型转换”和“sizeof”

  (b)b)malloc函数本身并不识别要申请的内存类型,它只关心内存的总字节数。

  (c)malloc返回值的类型是void*,所以在调用malloc时,需要显式转换类型,将void*转换成需要的指针类型。

  (d)statement free(p)之所以能正确释放内存,是因为事先知道指针p的类型和它所引用的内存的容量。如果p是空指针,那么无论free对p操作多少次,都不会有问题。如果p不是空指针,那么对p连续两次free操作都会导致程序运行不正确。

  9.使用新建/删除的要点

  (a)运算符new比函数malloc使用起来简单得多。这是因为new内置了sizeof、类型转换、类型安全检查等功能。对于具有非内部数据类型的对象,new在创建动态对象时完成初始化。如果一个对象有多个构造函数,new语句也可以有多种形式。

  例如:

  int * P1=(int *)malloc(sizeof(int)* length);

  int * p2=new int[length];

  (b)如果对象数组是用new创建的,那么只能使用对象的无参数构造函数。

  obj * objects=new obj[100];//创建100个动态对象

  (c)使用delete释放对象数组时,注意不要丢失符号“[]”。删除[]个对象;//正确用法

  10.野生指针

  3354“野指针”不是空指针,而是指向“垃圾”内存的指针。一般人不会误用空指针,因为用if语句很容易判断。但是“野指针”非常危险,if语句对它不起作用。

  “野指针”主要有两个原因:

  (a)指针变量未初始化。当创建任何指针变量时,它不会自动变成空指针。它的缺省值是随机的,它将是任意的。因此,指针变量应该在创建时初始化,要么将指针设置为NULL,要么指向合法内存。

  (b)指针P被释放或删除后没有设置为NULL,让人误以为P是合法指针。

  (c)指针操作超出了变量的范围。这种情况很难避免,

  1.内存分配方法

  有三种分配内存的方法:

  (a)从静态存储区分配。内存在程序编译时就已经分配好了,在程序的整个运行期内存都是存在的。比如全局变量,静态变量。

  (b)在堆栈上创建。函数执行时,可以在栈上创建函数中局部变量的存储单元,这些存储单元在函数执行结束时自动释放。堆栈内存分配内置在处理器的指令集中,效率非常高,但分配的内存容量有限。

  (c)从堆中分配,也称为动态内存分配。程序运行时,用malloc或new申请任意数量的内存,程序员负责什么时候用free或delete释放内存。动态记忆的寿命是由我们决定的。它使用起来非常灵活,但也有最多的问题。

  * *常见的内存错误及其对策

  1.内存分配不成功,但已被使用。

  新手程序员经常犯这个错误,因为他们没有意识到内存分配会不成功。常见的解决方法是在使用内存之前检查指针是否为空。如果指针p是函数的参数,使用assert(p!=NULL)进行检查。如果malloc或new用于申请内存,则为if(p==NULL)或if(p!=NULL)进行防错处理。

  2.虽然内存分配是成功的,但是在初始化之前引用它。

  造成这个错误的原因主要有两个:一是没有初始化的概念;二是误以为内存默认初始值都是零,导致引用初始值(比如数组)的错误。

  内存的默认初始值是什么,没有统一的标准,虽然有时候是零,但我们宁愿相信一切都是可信的。所以不管你怎么创建数组,别忘了赋初值,连零值都不能省略。不用麻烦了。

  3.内存分配成功并已初始化,但操作超出了内存边界。

  例如,下标“大于1”或“小于1”在使用数组时经常出现。尤其是在for循环语句中,循环次数容易弄错,导致数组运算越界。

  4.忘记释放内存,导致内存泄漏。

  包含此错误的函数每次被调用时都会丢失一段内存。一开始,系统有足够的内存,所以你看不到错误。最后程序突然死机,系统显示提示:内存耗尽。

  动态内存的申请和释放必须成对,malloc和free在程序中的使用次数必须相同,否则必然出错(new/delete也是如此)。

  5.释放内存但继续使用。(有三种情况:)

  (1)程序中的对象调用关系太复杂,确实很难知道一个对象是否释放了内存。这时候就要重新设计数据结构,从根本上解决对象管理混乱的局面。

  (2)函数的返回语句错误。注意不要将“指针”或“引用”返回到“堆栈内存”中,因为这个内存在函数体结束时会被自动销毁。

  (3)使用free或delete释放内存后,指针不设置为空。导致“野指针”。

  * *纠正预防措施:

  (a)用malloc或new申请内存后,应该立即检查指针值是否为空。防止使用指针值为空的内存。

  (b)不要忘记给数组和动态内存分配初始值。防止未初始化的内存被用作正确的值。

  (c)避免数组或指针的越界下标,特别要当心“多1”或“少1”的操作。

  (d)动态内存的应用和释放必须成对进行,以防止内存泄漏。

  (f)使用free或delete释放内存后,立即将指针设置为空,以防止“野指针”。

  12.指针和数组的比较

  (a)指针和数组在很多地方可以互换使用,但并不等价!

  (b)数组或者在静态存储区域(例如全局数组)中创建,或者在堆栈上创建。数组的名字对应(而不是指向)一块内存,它的地址和容量在生存期内保持不变,只有数组的内容可以改变。

  (c)指针可以在任何时候指向任何类型的内存块。它的特点是“易变”,所以我们经常用指针来操作动态内存。指针远比数组灵活,但也更危险。

  (d)如果要将数组A的内容复制到数组B,不能使用语句b=a,而应该使用标准库函数strcpy进行复制。

  (f)比较B和A的含量是否相同。不能用if(b==a)来判断,而要用标准库函数strcmp来比较。

  (g)语句p=a不是把A的内容复制到指针P,而是把A的地址赋给P,可以用库函数malloc为P申请一个strlen(a) 1字符的内存,然后用strcpy复制字符串。

  (h)语句if(p==a)比较的不是内容而是地址。应该和库函数strcmp比较一下。

  (I)数组的容量(字节数)可以通过使用操作符sizeof(注意不要忘记 \0 )来计算。

  (j)C /C语言没有办法知道指针所指的内存容量,除非在申请内存的时候记住。

  (k)注意,当一个数组作为函数的参数传递时,该数组会自动退化为相同类型的指针。(即函数中数组名的本质是对应的指针)。

  13.指针参数的转移存储器

  (a)如果函数的参数是指针,则指针不能用于申请动态内存。

  (b)如果你必须使用指针参数来申请内存,你应该使用指针对指针来代替。

  void GetMemory2(char **p,int num)

  * p=(char *)malloc(sizeof(char)* num);

  无效测试2(无效)

  char * str=NULL

  GetMemory2( str,100);//注意参数是str,不是str

  strcpy(str, hello );

  cout str endl

  免费(str);

  }

  (c)由于“指针对指针”的概念不容易理解,我们可以用函数返回值来传递动态内存。这个方法比较简单。

  char *GetMemory3(int num)

  char * p=(char *)malloc(sizeof(char)* num);

  返回p;

  无效测试3(无效)

  char * str=NULL

  str=get memory 3(100);

  strcpy(str, hello );

  cout str endl

  免费(str);

  }

  14.应对记忆衰竭。

  如果在申请动态内存时找不到足够大的内存块,malloc和new会返回一个空指针,声明内存申请失败。通常有三种方法来处理“内存耗尽”问题。

  (a)确定指针是否为空,如果是,立即用return语句终止该函数。

  无效函数

  A *a=新A;

  if(a==NULL)

  返回;

  }

  (2)判断指针是否为空,如果是,立即用exit(1)终止整个程序。例如:

  无效函数

  A *a=新A;

  if(a==NULL)

  cout“内存耗尽”endl

  出口(1);

  }

  (3)为new和malloc设置异常处理函数。例如,VisualC可以使用_ set _ new _ handler函数为new设置用户定义的异常处理程序,或者malloc可以享受与new相同的异常处理程序。详情请参考C用户手册。

  **(1)(2)模式是最常用的。如果一个函数中有多个地方需要申请动态内存,那么方法(1)是不够的(释放内存比较麻烦),应该用方法(2)来处理。

  江西理工大学理学院舍温整理

  2009-2-1723:27

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • office2010激活密钥大全 怎么永久激活office2010
  • project2010产品密钥免费_project2010激活密钥永久激活码
  • c语言调用退出函数 c语言退出整个程序怎么写
  • c语言中怎么给函数初始化 c语言的初始化语句
  • c语言编写函数计算平均值 c语言求平均函数
  • chatgpt是什么?为什么这么火?
  • ChatGPT为什么注册不了?OpenAI ChatGPT的账号哪里可以注册?
  • OpenAI ChatGPT怎么注册账号?ChatGPT账号注册教程
  • chatgpt什么意思,什么是ChatGPT ?
  • CAD中怎么复制图形标注尺寸不变,CAD中怎么复制图形线性不变
  • cad中怎么创建并使用脚本文件,cad怎么运行脚本
  • cad中快速计算器的功能,cad怎么快速计算
  • cad中快速修改单位的方法有哪些,cad中快速修改单位的方法是
  • cad中心点画椭圆怎么做,cad轴测图怎么画椭圆
  • CAD中常用的快捷键,cad各种快捷键的用法
  • 留言与评论(共有 条评论)
       
    验证码: