标签搜索

目 录CONTENT

文章目录

动态内存管理:malloc和free以及new和delete的联系与区别.md

小小城
2021-08-22 / 0 评论 / 0 点赞 / 4 阅读 / 3,746 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-02,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

动态内存管理:malloc和free以及new和delete的联系与区别

@[toc]

一、 C/C++中程序内存区域划分:

1. 内核空间:Linux系统对自身进行了划分,一部分核心软件独立于普通应用程序,运行在较高的特权级别上,它们驻留在被保护的内存空间上,拥有访问硬件设备的所有权限,Linux将此称为内核空间
2. 栈:又叫堆栈,非静态局部变量和函数参数及返回值都在栈上存储,栈是重上往下增长的。
3. 内存映射段:是高效的I/O映射方式,用于装载一个共享的动态内存库,用户可以使用系统接口创建共享共享内存,做进程间通信
4. 堆:用于程序运行时动态分配内存,堆是从下往上增长的
5. 数据段:存储静态数据和全局变量
6. 代码段:可执行时的代码和只读常量。

具体如下图:
在这里插入图片描述

二、C语言中动态分配内存管理方式:

  •  malloc:

  • 原型:

void *malloc(int byte_size);
  • 作用:动态开辟byte_size个字节的内存空间,不进行初始化,返回指向此内存的指针,此指针所指数据类型没有确定,需要强转

举例:

int *p=(int *)malloc(5*sizeof(int));
  • 例解:动态开辟5*4=20个字节大小的空间,返回空间首地址指针并强转为int *型后赋予指针变量p。

注意:malloc只开辟空间,不初始化,即只将此空间由未占用状态变为已占用状态,空间内存储的具体数据未指定改变。函数返回值是空间首地址,上例中赋给了p变量。

  •  calloc:

  • 原型:void *calloc(int n,int type_byte_size);

  • 作用:动态开辟n*type_byte_size个字节,将每个字节均初始化为ascii码0,返回指向此内存的指针,此指针所指数据类型没有确定,需要强转。

举例:int *p=(int *)calloc(5,sizeof(int));

例解:动态开辟5*4=20个字节大小的空间,其中每个字节均赋初值0,返回空间首地址指针并强转为int *型后赋予指针变量p。

  • 注意:calloc在malloc的基础上将空间按字节初始化为ascii码0,且其参数有两个,两参数之积为空间总字节数。

realloc:

原型:

void *realloc(void *p,int byte_size);
  • 作用:对空间进行调整,若p为空,则该函数与malloc相同
  • 若p所指空间连续大小(单位字节)大于byte_size,则从首地址开始连续地扩充开辟p所指空间至byte_size字节,不对空间再次赋值,将空间地址指针返回;
  • 若p所指空间连续大小小于byte_size,则新开辟byte_size字节大小的空间,将p指向的空间内的数据复制进新空间,之后释放p所指空间(此时p为NULL),返回指向新空间的指针,此指针所指数据类型没有确定,需要强转。

举例:

int *p=(int *)calloc(5,sizeof(int));
p =(int*)realloc(p,10*sizeof(int));
  • 例解:首句中p为5*4=20字节的空间指针并按字节初始化为ascii码0,(int*)强转后才限定了指向空间的每个元素为int型。

  • 后句将p所指空间扩充为10*4=40字节的空间指针,未对其二次赋值,故此时p[0]~p[4]为0,p[5]~p[9]未初始化

注意:realloc的第一个参数必须是动态开辟的地址,不能是静态定义的数组的地址,结构体数组也不行。

  •  free:
  • C 库函数 *void free(voidptr)** 释放之前调用 calloc、malloc 或 realloc所分配的内存空间
  • ptr-- 指针指向一个要释放内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果传递的参数是一个空指针,则不会执行任何动作。
  • 该函数不返回任何值

下面的实例演示了 free() 函数的用法:

 #include <stdio.h>
 int main()
{   
    char *str;    /* 最初的内存分配 */   
    str = (char *) malloc(15);   
    strcpy(str, "jikexueyuan");   
    printf("String = %s,  Address = %un", str, str);   /* 重新分配内存 */   
    str = (char *) realloc(str, 25);   
    strcat(str, ".com");  
     printf("String = %s,  Address = %un", str, str);   /* 释放已分配的内存 */   
    free(str);   return(0);
    }

让我们编译并运行上面的程序,这将产生以下结果:

String = jikexueyuan, Address = 355090448String = jikexueyuan.com, Address = 355090448

三、C++内存管理方式

  •  new/delete操作内置类型:
void Test()
{
	// 动态申请一个int类型的空间
	int* ptr4 = new int;
	// 动态申请一个int类型的空间并初始化为10
	int* ptr5 = new int(10);
	// 动态申请10个int类型的空间
	int* ptr6 = new int[3];
	delete ptr4;
	delete ptr5;
	delete[] ptr6;
}

注意:申请和释放单个元素空间,使用new/delete操作符,申请和释放连续元素空间,使用new[]/delete[]操作符。

  •  new/delete操作自定义类型:
class Test
{
public:
	Test()
	: _data(0)
	{
		cout<<"Test():"<<this<<endl;
	}
	~Test()
	{
	cout<<"~Test():"<<this<<endl;
	}
private:
	int _data;
};

void Test2()
{
	// 申请单个Test类型的空间
	Test* p1 = (Test*)malloc(sizeof(Test));
	free(p1);
	// 申请10个Test类型的空间
	Test* p2 = (Test*)malloc(sizoef(Test) * 10);
	free(p2);
	}
void Test2()
{
	// 申请单个Test类型的对象
	Test* p1 = new Test;
	delete p1;
	// 申请10个Test类型的对象
	Test* p2 = new Test[10];
	delete[] p2;
}

注意:在申请自定义类型空间时,new会调用类的构造函数,delete会调用类的析构函数,malloc和free不会调用

  •  new和delete的实现原理:

  • a、如果申请的是内置空间

  • 那么new/delete,malloc/free就没有太大区别。

  • 不同的地方主要有如果malloc申请空间失败,则会返回NULL,所以在用之前要进行判空处理。

  • 而new操作符申请空间时,如果失败,就会优先进行调整,若没有调整操作,就会抛出异常。

  • b、如果申请的是自定义空间:

  • new的原理为:

  • 首先调用operator new函数申请一个空间,而operator new函数则采用循环的方式,用malloc来进行申请空间

  • 若申请空间失败,就会优先进行调整操作,直到申请成功,若没有调整操作,就会抛出异常。

  • 注意此时并没有申请成功,只是相当于申请了以个大小相同的空间而已,此时该对象是不完整的

  • 所以最后进行的操作是在申请的空间上执行类的构造函数,完成对象的构造。

  • delete的原理为:

  • 首先为了防止内存泄漏,在该空间上执行类的析构函数,完成对象资源清理工作,最后调用operator delete函数,释放该对象的空间。

  • new[N]的原理为:

  • 调用operator new[] 函数,而在operator new[]中实际调用operator new函数完成对N个对象空间的申请操作,最后在申请的空间上执行N次构造函数,完成对N个对象的申请。

  • delete[]原理为:

  • 在申请的空间上执行N次析构函数,完成对N个对象的资源清理工作,最后在调用operator delete[] 函数,而在operator delete[]函数中实际调用operator delete函数完成对N个对象空间的释放回收操作。

四、malloc/free与new/delete的区别:

malloc/freenew/delete
是标准库内的函数是关键字,不是函数
malloc申请的空间不会初始化new出来的空间可以初始化
malloc申请空间时,需要手动计算申请空间的大小并传递new不需要,只需在后面跟空间的类型
malloc的返回值为void*,所以在使用时要进行强转操作new后跟的就是空间的类型
malloc申请空间失败会返回NULL,所以使用时需要判空new申请空间失败会抛出异常
在申请自定义空间时,malloc/free只负责开辟空间,和释放空间,不会调用构造函数和析构函数new会在申请空间后调用构造函数完成对象的初始化,delete会在释放空间前调用析构函数完成资源清理工作。
0

评论区