引言
所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。
C/C++定义了4个内存区间:代码区,全局变量与静态变量区,局部变量区即栈区,动态存储区,即堆区或自由存储区。
堆的概念
通常定义变量(或对象),编译器在编译时都可以根据该变量(或对象)的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的存储空间。这种内存分配称为静态存储分配;有些操作对象只在程序运行时才能确定,这样编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。所有动态存储分配都在堆区中进行。当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存贮空间,用于存贮该变量或对象。当不再使用该变量或对象时,也就是它的生命结束时,要显式释放它所占用的存贮空间,这样系统就能对该堆空间进行再次分配,做到重复使用有限的资源。
在使用数组的时候,总有一个问题困扰着我们:数组应该有多大?在很多的情况下,你并不能确定要使用多大的数组,比如上例,你可能并不知道我们要定义的这个数组到底有多大,那么你就要把数组定义得足够大。这样,你的程序在运行时就申请了固定大小的你认为足够大的内存空间。即使你知道你想利用的空间大小,但是如果因为某种特殊原因空间利用的大小有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。但是这种内存分配的方法存在比较严重的缺陷,特别是处理某些问题时:在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。
我们用动态内存分配就可以解决上面的问题. 所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。
从以上动、静态内存分配比较可以知道动态内存分配相对于静态内存分配的特点:
1、不需要预先分配存储空间;
2、分配的空间可以根据程序的需要扩大或缩小。
实现
在C++中,动态内存的分配主要由new 运算符与delete 运算符来完成(有别于C语言中的malloc族 函数 )
new
申请一个存储单元,返回首地址的指针,或者NULL
<指针> = new <elemType>;
int *temp = new int;
申请一个数组
<指针> = new <elemType>[常量表达式];
int *temp = new int[MAXSIZE];
申请一个二维数组
<指针> = new <elemType>[常量表达式1][常量表达式2];
int *temp = new int[MAXSIZE1][MAXSIZE2];
delete
释放new申请到的内存(一定要记得!!!最好在写下new的时候就一并写下delete,然后再在二者之间填充语句)
delete p;
or delete [ ]p;
注意事项
- 在程序中每次使用new,都要相应的使用delete来释放内存,并且对于每个new,只能调用一次delete,否则可能导致系统崩溃
- 运算符delete必须用于先前new分配的有效指针,而不能用于未定义的其他任何类型的指针(野指针、不是new申请的都不行)
- 对空指针(指向NULL)调用delete是安全的
为什么要是new?
既然malloc( )和free( )库函数可以实现动态分配的需要,为什么还要new和delete呢?
// 都是类的fault
这是因对于非内部数据类型的对象而言,只用库函数malloc( )和free( )无法满足动态对象的要求。我们知道,对象在创建的同时要执行构造函数,对象在消亡之前要执行析构函数。由于malloc( )和free( )是库函数而不是运算符,不在编译器的控制权限之内,不能把执行构造函数和析构函数的任务强加于它们
补充:new的三种面貌
(引用Dablelv的博文)不说啦,直接贴链接吧🔗