C/C++内存分布
栈:存储非静态局部变量、函数参数、返回值。
内存映射段:动态库。
堆:程序运行时动态内存分配。
数据段:存储全局变量、静态数据。
代码段:可执行代码,只读常量。
C语言中动态内存管理
-
malloc函数
-
void* malloc(size_t number)
-
在堆中动态申请一块长度为numbre个字节的连续区域,返回该区域的首地址,但是返回类型为void* ,在使用时需要对其进行类型转换,并且该块区域没有进行初始化,如果想对其进行整体初始化,可以结合memset函数对其进行初始化操作。
-
void memeset(void* buf,int c,int count) ,buff为该区域的首地址,c为初始化的值,count为区域的大小。
-
注意 malloc申请空间时,有可能会失败,所以在使用malloc申请出来的空间,需要对其进行判空操作。
-
calloc函数
-
void* calloc(size_t number,size_t size)
-
number为申请空间的元素个数,size为每个元素大小,用calloc申请空间的总大小为number*size。
-
calloc在申请空间时,默认对其区域进行初始化操作,默认初始化的值为0。
-
注意 calloc申请空间时,有可能会失败,所以在使用calloc申请出来的空间,需要对其进行判空操作。
-
realloc函数
-
void* realloc(void* buff,size_t new_size)
-
realloc对malloc申请的空间调整其大小,buff为空间的首地址,new_size为将原空间大小调整到。new_size可以比原空间大,也可以比原空间小。
-
注意 realloc申请空间时,有可能会失败,所以在使用realloc申请出来的空间,需要对其进行判空操作。
-
malloc/calloc/realloc区别
-
malloca函数对申请到的空间不能进行初始化,calloc会对申请的空间同时进行初始化。calloc会将指针类型初始化为空指针,数据类型初始化为0。realloc如果对内存缩小,缩小的一部分数据会丢失,当其对内存扩大时,编译器会先在其原本内存的后面进行扩展,如果位置不足,则会重新开辟一块内存空间,最终进行数据的搬移,返回的指针很可能是一个新的地址。
-
不论是用上面哪个函数申请空间,申请的空间都用free释放。void free(void* buff),buff为申请空间的首地址。用free释放完空间后,需要手动将原空间的首地址赋值为NULL,避免出现野指针。
C++内存管理操作
- new / delete 申请内置类型
void TestFunc()
{
int* p1 = new int; //申请int类型的空间;
int* p2 = new int(3); //申请一个int类型的空间并对其初始化为3;
int* p3 = new int[3]; //申请3个int类型的空间,相当于申请int类型的数组
}
- 申请自定义类型
class Date
{
public:
Date()
{
cout<<"Date()构造函数"<<endl;
}
~Date()
{
cout<<"~Date()析构函数"<<endl;
}
private:
int d;
};
void TestFunc()
{
//malloc申请1个自定义类型的空间
Date* p1 = (Date*)malloc(sizeof(Date));
free(p1);
//new申请一个自定义类型的空间
Date* p2 = new Date;
delete p2;
}
在申请空间上忙new申请的空间会调用构造函数,malloc只会申请出一个空间,delete会调用析构函数,free不会。
注意 :在申请空间与释放空间时,new与delete,malloc与free必须成对出现。否则会出现错误。
new[]/delete[]
- new[]同时申请多个空间,delete[]同时对多个空间进行释放。
int* p1 = new int[10]; //申请10个int型空间
delete[] p1;
Date* p2 = new Date[10]; //申请10个自定义类型空间
delete[] p2;
new底层实现原理
new申请空间会进行两步操作,第一步是申请空间,第二步为调用构造函数进行初始化操作。
- 第一步:申请空间,底层代码
void* operator new(size_t size)
{
//底层调用malloc函数循环申请空间
malloc循环申请空间;
if(申请失败)
提供空间不足的措施;
else
直接退出;
}
- 第二步:调用构造函数完成初始化操作。
delete底层原理
- void operator delete()。
- 第一步调用析构函数,释放对象中的资源
- 在释放对象资源结束前最后一句,调用free()函数,释放对象空间。
operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete最终是通过free来释放空间。
new[ ]底层原理
- void* operator new[](size_t size) 内部调用void* operator new(size_t size)函数。
- 调用operator new[]函数,在operator new[]中实际调用operator new函数完成对多个对象空间的申请。
- 在申请空间上执行多次构造函数。
delete[ ]底层原理
- void operator delete[]
- 调用多次析构函数,完成多个对象的资源清理工作。
- 执行operator delete[]释放空间,实际上是调用operator delete函数来释放空间。