内存管理
一,C/C++内存分布
从用途和存储的角度来看,在C/C++程序中有局部数据、静态数据、全局数据、常量数据、动态申请的数据五种主要的数据,各种数据的特点如下:
- 局部数据:随用随创建,存储在栈区,作用域只在局部,生命周期在局部,出了作用域就销毁。
- 静态数据:存储在数据段,作用域只在局部或当前文件,生命周期伴随程序“一生”。
- 全局数据:存储在数据段,作用域在全局,生命周期伴随程序“一生”。
- 常量数据:存储在代码段。
- 动态申请的数据:存储在堆区。
小Tips:这里需要注意char char2[] = “abcd”;,"abcd"是常量字符串,存储在代码段,但是char2只是一个局部域的数组,它会把这个常量字符串拷贝一份,存储在栈区,然后char2是数组名,表示数组首元素的地址,这里表示的就是拷贝过来存储在栈区的字符串的首元素地址,并不是表示代码段中常量字符串的首元素地址。其次,const并不会改变变量的存储区域,因为pChar3是一个局部变量,所以它还是存储在栈区,前面加const修饰,是因为它存的是代码段中常量字符串的首地址。可见只要是在局部创建的变量,只要前面没有加static修饰,那这个变量一定是存储在栈区。
📖总结:
- 栈:又叫堆栈,用于存放非静态局部变量、函数参数、返回值等等,栈是向下生长的。
- 内存映射段:是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享内存,做进程间通信。
- 堆:用于程序运行时动态内存分配,堆是向上增长的。
- 数据段:用于存储全局数据和静态数据。
- 代码段:用于存储可执行的代码/只读的常量。
二,C/C++内存管理方式
在学习C语言时,提到的4个内存管理函数malloc、realloc、calloc、free大家还记得嘛👀?忘了的话可以走传送门,回去看看。在C++中我们任然可以使用C语言中的内存管理方式,但有些地方就无能为力了,而且使用起来比较麻烦,因此C++中提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
2.1 new和delete操作内置类型
void Test()
{
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请10个int类型的空间,不初始化
int* ptr6 = new int[10];
// 动态申请10个int类型的空间,并初始化前三个
int* ptr7 = new int[10]{
1,2,3};
delete ptr4;
delete ptr5;
delete[] ptr6;
delete[] ptr7;
}
小Tips:new对内置类型来说,和C语言一样,只是纯粹的开空间,对于动态申请到的空间,如果不进行人为初始化的话,里面存的都是随机值。动态申请并初始化,类型后面跟的是圆括号(),动态申请多个连续空间,类型后面跟的是方括号[],如果要对这多个连续的空间初始化,可以在[]的后面跟{},里面是初始化的数据,可以只初始化一部分,后面默认补0。申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间使用new[]和delete[]。
2.2 new和delete自定义类型
📖C语言的玩法
先来回顾一下,C语言中针对自定义类型是怎么玩的,以动态申请一个链表节点为例:
//节点类型
struct List_Node
{
int _val;
struct List_Node* _next;
};
//申请节点的函数
List_Node* BuyListNode(int x)
{
List_Node* tmp = (List_Node*)malloc(sizeof(List_Node));
if (nullptr == tmp)
{
perror("malloc");
exit(-1);<