动态内存管理

一.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在释放空间前会调用析构函数完成 空间中资源的清理 .

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值