动态内存管理

avatar
作者
猴君
阅读量:2

一.C语言中内存管理:

我们学过的掌握申请内存,有申请数组的连续空间和内置类型的空间,但这两个都有局限性,不能申请动态内存管理,所以我们还要继续学习如何申请动态内存管理。

(一).malloc函数:

C语言中提供了一个函数malloc可以动态申请连续空间。

这个函数可以申请一块连续的空间,并且返回类型是指针。如果开辟成功则返回申请成功的地址指针,若开辟失败则返回NULL,所以我们在malloc申请完空间后一定要进行检测是否申请成功,如果size为0,则未定义取决于编译器。

C语言还提供了free函数,用来释放空间,以防内存泄漏。 

如果ptr不是动态空间,则此时free'行为是未定义的;若ptr是NULL,不用进行。

int main() { int*p=((int*)malloc(sizeof(int)*10)); if(p=NULL) { perror("malloc"); return 1; } //此时p的动态空间已经申请成功,用free函数释放空间 //但是要用p置为NULL,因为 这里free函数相当于传值,形参是实参的拷贝 free(p); p=NULL; return 0;

(二).calloc函数:

C语言中还提供了一种calloc函数,和malloc函数功能基本相似都是申请动态空间,但是不同的是calloc函数在申请动态空间成功后,会对其进行初始化为0. 

其中num表示有num个大小为size的申请空间。

函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。  

int main() { int*b=(int*)calloc(10,sizeof(int); if(P!=NULL) { } int i=0; for(int i=0;i<10;i++) { *(p+i)=i; } for(int i=0;i<10;i++) { printf("%d",*(p+i)); } free(p); p=NULL; 

(三).realloc函数:

realloc函数的出现让动态内存管理更加灵活。 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时 候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。   

其中ptr 是要调整的内存地址 size 调整之后新大小 返回值为调整之后的内存起始位置。 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。

注意:realloc在调整空间时候一般会遇到两种情况:(1).原有空间后面有足够大的空间,此时我们可以直接在原有空间的后面继续进行申请。(2).原有空间后面不足,此时我们需要扩展,在堆上重新找一个大小合适的空间进行申请,并且将旧的复制到新的空间中,释放掉旧的,这样函数就会返回一个新的地址。 

 (四).常见的动态内存错误:

(1).对NULL解引用错误使用

(2).对动态开辟空间的越界访问

(3).用free函数释放同一块空间

(4).用free函数释放动态空间的一部分,这是错误的,在释放的时候我们必须从空间的最开始进行释放。

(5).动态空间忘记释放,造成内存泄漏。

二.C++语言中内存管理:

(一).new/delete操作内置类型

在进行内存管理的讲解之前先看一下下面的题;

int globalVar = 1;          static int staticGlobalVar = 1;        void Test() { static int staticVar = 1;         

 int localVar = 1;            int num1[10] = { 1, 2, 3, 4 };           char char2[] = "abcd";                       const char* pChar3 = "abcd";               int* ptr1 = (int*)malloc(sizeof(int) * 4);                                  int* ptr2 = (int*)calloc(4, sizeof(int));            int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);    free(ptr1); free(ptr3); }

1. 选择题:   选项: A.栈  B.堆  C.数据段(静态区)  D.代码段(常量区)   globalVar在哪里?____   staticGlobalVar在哪里?____   staticVar在哪里?____   localVar在哪里?____   num1 在哪里?____     char2在哪里?____   *char2在哪里?___   pChar3在哪里?____      *pChar3在哪里?____   ptr1在哪里?____        *ptr1在哪里?____

1.动态申请一个内置类型的空间:

//动态申请一个int类型的空间 int*a=new int; //动态申请一个int类型的空间并且初始化 int *b=new int(3);//初始化为3 //动态申请多个int类型的空间 int *c=new int[10]; //动态申请多个int类型的空间并且 初始化 int *d=new int[10]{0,1,2,3,4}//前五个值初始化为给定的值,剩余五个值默认为0 
//动态清理空间 delete a; delede []c;//注意:多个值的时候要在delete后面加[],内置定义类型可以不加,但是自定义类型必须加 

注意:申请和释放单个元素的空间时候,用new和delete,若是申请和释放多个元素的空间时候,用new[]和delete[]结合使用。

2.动态申请自定义类型的 空间;

class A { public:  A(int a=0)  {   :_a(a);   {  cout<<"A():"<<this<<endl;   }  } ~A(int a=0) {   cout<<"~A():"<<this<<endl; } private: {  int _a; } int main() { A*p1=(A*)malloc(sizeof(A)); free(p1); A*p2=new A(1); delete P2;

若使用malloc给自定义对象申请空间 ,则只会开辟空间,但是用new申请空间,则会调用构造函数先初始化,然后申请空间,同理若使用delete,则先调用析构函数,然后释放掉空间。

类中有多个对象可以调用多次构造函数,然后每个函数调用一次析构函数。

int*p3=(int*)malloc(sizeof(int)); free(p3); int *p4=new int(5); delete p4;

但是如果是处理内置类型,使用malloc和new,free和delete效果一样。 注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

3.operator new和operator delete函数:

new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是 系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数释放空间。operator new 实际也是通过malloc来申请空间,如果 malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施 就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。   

4.new和delete的实现原理:

(1).内置类型;如果申请的是内置类型,则malloc、free、new和delete基本效果一样,new/delete申请或者销毁的是单个元素的空间,new[]和delete[]申请或者销毁的是多个元素的空间,如果申请失败,malloc则会返回NULL,new抛出异常。

(2).自定义类型

new的原理:先用operator new函数申请空间然后调用构造函数在申请的空间上进行初始化。

delete的原理:先调用析构函数完成对象中的资源清理,再使用operator delete函数释放对象的空间。

new Q[N]:先用operator new[] 函数对N个对象申请空间,再调用构造函数在申请的空间上对N个值进行初始化。

delete Q[N]:先调用析构函数完成N个对象中的资源清理,再使用operator  delete函数释放N个对象的空间。

5.定位new表达式:

概念:定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。 使用格式: new (place_address) type或者new (place_address) type(initializer-list) place_address必须是一个指针,initializer-list是类型的初始化列表  。如 果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

class A { public:    A()  {   :_a(a);    {      cout<<"A():"<<this<<endl;    }    }    ~A()  {     cout<<"~A():"<<this<<endl;   } } int main() {  A*p1=(A*)malloc(sizeof(A)); //使用new调用构造函数初始化 new(p1)A; //调用构造函数清理对象中的资源 p1->~A(); free(p1); A*p2=(A*)malloc(sizeof(A)); new(p2)A; p2->~A(); //使用operator delete释放空间 operator delete(p2); return 0; } 

定位new的表达式:new(对象)类型。 

6. malloc和new的区别:

malloc/free和new/delete的区别 :

malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。

不同的地 方是: 1. malloc和free是函数,new和delete是操作符

2. malloc申请的空间不会初始化,new可以初始化

3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个对象,[]中指定对象个数即可

4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型

5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需 要捕获异常

6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new 在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成 空间中资源的清理 .

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!