malloc与free是C/C++的标准库函数,new/delete是C++的关键字。它们都可用于申请动态内存和释放内存。
使用动态内存很明显的好处就是:不需要预先分配存储空间且分配的空间可以根据程序的需要扩大或缩小,这样可以有效的使用内存空间。
对于非内部数据类型的对象而言,光用malloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象的消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
1、malloc和free
#include <malloc.h>
#include <alloc.h>
#include <stdlib.h>
三者其中一个就行。
void *malloc(size_t size);//返回指向内存块首地址的指针,指针类型是void*,所以后续需要转换 void free(void *pointer);
使用示例:
int *p=(int *)malloc(100); //指向整型的指针p指向一个大小为100字节的内存的地址, int *p=(int *)malloc(25*sizeof(int)); //指向整型的指针p指向一个25个int整型空间的地址 /*如果分配失败了,会返回一个空指针,所以分配内存后必须要验证内存是否成功分配!!完成后用free()释放内存*/ int *p=(int *)malloc(int); if(p==NULL) printf("Out of memory!\n"); free (p);
calloc
void *calloc ( size_t num_elements, size_t element_size );//所需元素的数量,每个元素的字节大小
类似于malloc,主要区别是在返回内存的指针之前将它初始化为0。
realloc
void *realloc (void *ptr, size_t new_size );//内存块的首地址,字节大小
函数用于修改一个原先已经分配的内存块的大小,可以使一块内存的扩大或缩小。
当起始空间的地址为空,即*ptr = NULL,则同malloc。
当*ptr非空:
- 若new_size < size,即缩小*ptr所指向的内存空间,该内存块尾部的部分内存被拿掉,剩余部分内存的原先内容依然保留;
- 若new_size > size,即扩大*ptr所指向的内存空间,如果原先的内存尾部有足够的扩大空间,则直接在原先的内存块尾部新增内存
如果原先的内存尾部空间不足,或原先的内存块无法改变大小,realloc将重新分配另一块new_size大小的内存,并把原先那块内存的内容复制到新的内存块上。因此,使用realloc后就应该改用realloc返回的新指针。
2、new、delete
c++中,对内存重新定义:堆、栈、自由存储区、全局/静态存储区、常量存储区
malloc/free是在堆上分配的内存块,使用free释放内存,而new所申请的内存则是在自由存储区上,使用delete来释放。
堆和自由存储区的区别?
自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,只要是通过new申请的内存区域,就可以成为自由存储区。其实,所有c++的编译器默认使用堆来实现自由存储,也就是new/delete会按照malloc/free的方式申请内存,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。
因此:堆是操作系统维护的一块内存,是官方术语。而自由存储是C++中通过new与delete动态分配和释放对象的抽象概念。堆与自由存储区并不等价。
用法
int *pi=new int;//在自由存储区中分配创建了一个整形对象,并返回一个指向该对象的地址来初始化指针pi。 int *pi=new int();//加括号是对指针指向的地址的值初始化为0 int *pi=new int(1024);//地址初始化为1024
用完后必须释放,避免造成内存泄漏。使用delete完成:
delete pi;//此时·pi尽管没有定义,但仍然存放了它所指向对象的地址,然而pi所指向的内存已经被释放,因此pi不再有效。 p=NULL;//一旦删除指针所指向的对象,立即将指针置为0,这样就清楚的表明指针不再指向任何对象。
创建一个动态数组对象和进行内存释放时,执行以下语句:
int *pi=new int[]; //指针pi所指向的数组未初始化 int *pi=new int[n]; //指针pi指向长度为n的数组,未初始化 int *pi=new int[](); //指针pi所指向的地址初始化为0 delete [] pi; //回收pi所指向的数组
3、new和malloc区别
1、申请内存的位置
new从自由存储区为对象分配内存,malloc从堆上分配。
自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。
2、参数
new不需要指定内存大小;
mallco需要显示指定(sizeof(type)*n);
3、返回值
new操作符分配成功,返回对象类型指针,不用类型转换;new失败,抛出异常,不返回NULL;
malloc分配成功,返回void*(无类型指针),需要强制类型转换成对象类型指针;malloc失败,返回NULL;
4、调用构造函数、析构函数
new:调用operator new分配足够大的内存,运行构造函数,返回对象指针。
delete:调用对象的析构函数,调用operator delete释放空间。
而malloc不会
特征 | new/delete | malloc/free |
---|---|---|
分配内存的位置 | 自由存储区 | 堆 |
内存分配成功返回值 | 完整类型指针 | void* |
内存分配失败返回值 | 默认抛出异常 | 返回NULL |
分配内存的大小 | 由编译器根据类型计算得出 | 必须显式指定字节数 |
处理数组 | 有处理数组的new版本new[] | 需要用户计算数组的大小后进行内存分配 |
已分配内存的扩充 | 无法直观地处理 | 使用realloc简单完成 |
是否相互调用 | 可以,看具体的operator new/delete实现 | 不可调用new |
分配内存时内存不足 | 客户能够指定处理函数或重新制定分配器 | 无法通过用户代码进行处理 |
函数重载 | 允许 | 不允许 |
构造函数与析构函数 | 调用 | 不调用 |
使用动态分配的内存的基本规则
●避免分配大量的小内存块。分配堆上的内存有一些系统开销,所以分配许多小的内存块比分配几个大内存块的系统开销大。
●仅在需要时分配内存。只要使用完堆上的内存块,就释放它。
●总是确保释放已分配的内存。在编写分配内存的代码时,就要确定在代码的什么地方释放内存。
●在释放内存之前,确保不会无意中覆盖堆上分配的内存的地址,否则程序就会出现内存泄漏。在循环中分配内存时,要特别小心。