new / malloc / calloc / realloc都能在堆上动态开辟空间,那么他们之间有什么区别呢??
下面先对上述的操作符或者函数逐个介绍
目录
一、malloc函数
malloc 按字节大小申请空间,但不会初始化
函数声明:void* malloc (size_t size);
参数:申请空间所占字节数( = 申请的元素个数num * 每个元素所占的字节数)
返回值:申请成功时,返回空间地址;申请失败时,返回NULL
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 10;
int* pData = (int*)malloc(num * sizeof(int));
if(pData == NULL)
{
printf("申请空间失败");
}
}
二、calloc函数
calloc 按字节大小申请空间,同时会初始化为 0
函数声明: void* calloc (size_t num, size_t size);
第一个参数:申请开辟 num 个元素的空间大小
第二个参数:每个元素所占字节数
返回值:申请成功时,返回空间地址;申请失败时,返回NULL
#include <stdio.h>
int main()
{
int num = 10;
int* pData = (int*)calloc(num , sizeof(int));
if(pData == NULL)
{
printf("申请空间失败");
}
}
三、realloc函数
realloc 在已经申请好内存块的基础上,重新分配,但不会初始化
(1)若之前没有申请,那么直接分配,和malloc用法一致
(2)若已经申请过了,就有两种情况
- 新分配的内存块比原来大,
在原来的基础上新增 或者 在其他地方开辟一块空间,将数据拷贝进去,释 放原本的空间
- 新分配的内存块比原来小,在原本的基础上削减
函数声明:void* realloc (void* ptr, size_t size);
第一个参数:已经申请过的空间地址(若未申请,则填NULL)
第二个参数:申请空间所占字节数( = 申请的元素个数num * 每个元素所占的字节数)
返回值:申请成功时,返回空间地址;申请失败时,返回NULL
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num = 10;
int* pData = (int*)realloc(num, sizeof(int));
if (pData == NULL)
{
printf("申请空间失败");
}
}
四、new操作符
new 按照元素个数申请空间,自动检测元素类型,计算所需字节数
中括号 [ ]:申请多个元素的空间
小括号 ( ):申请一个元素的空间,给这个空间初始化
无括号:申请一个元素的空间,但不初始化
1、给内置类型开辟空间
#include <stdio.h>
#include <stdlib.h>
int main()
{
//动态申请10个int类型的空间
int* pData1 = new int[10];
//不需要时,通过delete把空间释放
delete[] pData1;
//动态申请一个int类型的空间,不初始化
int* pData2 = new int;
delete pData2;
//动态申请一个int类型的空间,初始化为10
int* pData3 = new int(10);
delete pData3;
}
注意:
释放多个元素的空间时,要使用delete[ ],加了[ ],编译器会自动计算申请了几个元素
释放一个元素的空间时,直接使用delete 即可
2、给自定义类型开辟空间
使用new给自定义类型开辟空间的方式 和前面一样,但不一样的是,使用new给自定义类型开辟空间时,会调用构造函数;释放空间,会调用析构函数
#include <stdio.h>
#include <stdlib.h>
class A
{
public:
A()
{
printf("A的默认构造函数被调用了\n");
}
private:
int _a;
};
int main()
{
A* pa = new A;
//A* pa = new A[10];
delete pa;
}
申请一个对象,相当于创建了一次对象,会调用一次构造函数
申请10个对象,相当于创建了10次对象,会调用10次构造函数
五、new/delete的底层调用
operator new 和operator delete是系统提供的全局函数
-》new在底层调用operator new全局函数来申请空间,operator new再去调用malloc
申请成功则直接返回
申请失败会抛出异常,而不是像malloc一样返回null
-》delete在底层通过operator delete全局函数来释放空间
六、malloc底层实现
malloc采用的是内存池的管理方式,以减少内存碎片。先申请大块内存作为堆区,然后将堆区分为多个内存块。当用户申请内存时,直接从堆区分配一块合适的空闲快。采用隐式链表将所有空闲块连接,每一个空闲块记录了一个未分配的、连续的内存地址。
- 当开辟的空间小于 128K 时,调用 brk 函数
- 当开辟的空间大于 128K 时,调用 mmap 函数
七、new和malloc 的区别
1、new是操作符,malloc是函数(定义的角度)
2、new的参数是申请的元素个数,malloc的参数是 申请空间所占字节数(参数的角度)
3、malloc的返回值是 void*,必须要强转,new不需要(返回类型)
4、给自定义类型开辟空间时,new会调用构造函数,malloc不会(特殊情况,自定义类型)
5、new发生错误是抛异常,malloc返回null