作者:chlorine
专栏:c++专栏
目录
💻 C/C++内存分布
💻C语言中动态内存管理方式:malloc/calloc/realloc/free
编辑
💻C++内存管理方式
👉new/delete操作内置类型
👉new和delete操作自定义类型
💻operator new与operator delete函数(重要点进行讲解)
💻new和delete的实现原理
👉内置类型
👉 自定义类型
💻常见面试题
malloc/free和new/delete的区别
💻 C/C++内存分布
我们先来看一下下面的一段代码吧
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
1. 选择题:
选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?_C___ staticGlobalVar在哪里?_C___
staticVar在哪里?__C__ localVar在哪里?__A__
num1 在哪里?___A_上面的几个变量的位置在哪大家肯定很清楚,下面几个变量就有些难度了。
选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
- char2在哪里?__A__ * char2在哪里?_A__
字符串默认是常量字符串存储常量区,而char2是开辟的数组存储在栈区
将字符串拷贝给数组(数组是初始化)。但是我们要知道数组名是数组首元素的地址。
char2是数组首元素的地址,对数组首元素的地址解引用是'a'不再常量区,而是栈区。因为字符串已经拷贝给数组,数组在栈区那么字符串就在常量区。所以这里是大家出错的地方,我一开始也选的是D,但是我们要知道字符串虽然存储在常量区,但是我们要给新开辟的数组初始化,就得给堆区的字符串拷贝给数组。选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
- pChar3在哪里?_A_ * pChar3在哪里?_D__
- const char* pChar3 = "abcd";
pChar3是指针变量,存储在栈区,这是毋庸置疑的。字符串默认是常量字符串存储在常量区。pchar3是指向常量区"abcd\0"的地址,*pchar3是对常量区的"abcd\o"字符串解引用,找到字符串中a字符的,所以在字符串在哪*pchar就在哪。所以*pChar3存储在常量区。
选项 : A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
- ptr1在哪里?_A___ * ptr1在哪里?__B__
- int* ptr1 = (int*)malloc(sizeof(int) * 4);
ptr1是指针变量,在栈区,而表达式后面malloc其实是在堆上malloc个空间,*ptr1指向那块开辟的空间并对其解引用,找到那块空间,所以在*ptr1在堆区。
2. 填空题:int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";const char* pChar3 = "abcd";
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
sizeof(num1) = _40___;
sizeof(char2) = _5___; strlen(char2) = __4__;
sizeof(pChar3) = __4/8__; strlen(pChar3) = _4/8___; 指针4/8字节
sizeof(ptr1) = _4/8___;
【说明】
- 1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。
- 2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
- 创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)
- 3. 堆用于程序运行时动态内存分配,堆是可以上增长的。
- 4. 数据段--存储全局数据和静态数据。
- 5. 代码段--可执行的代码/只读常量。
💻C语言中动态内存管理方式:malloc/calloc/realloc/free
malloc
calloc
realloc
free
💻C++内存管理方式
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因 此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理 。
👉new/delete操作内置类型
voidTest()
{
// 动态申请一个int类型的空间
int*ptr4=new int;
// 动态申请一个int类型的空间并初始化为10
int*ptr5=new int(10);
// 动态申请10个int类型的空间
int*ptr6=new int[10];
delete ptr4;
delete ptr5;
delete[] ptr6;
}
如果我们想申请3个int类型的空间,并初始化1,2,3.
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用 new[]和delete[],注意:匹配起来使用。
👉new和delete操作自定义类型
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间
//还会调用构造函数和析构函数
A* p1 = (A*)malloc(sizeof(A));
A* p2 = new A(1);
free(p1);
delete p2;
return 0;
}
💻operator new与operator delete函数(重要点进行讲解)
- operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间 失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
- operator delete: 该函数最终是通过free来释放空间的
💻new和delete的实现原理
👉内置类型
👉 自定义类型
- new的原理
1. 调用operator new函数申请空间2. 在申请的空间上执行构造函数,完成对象的构造
- delete的原理
1. 在空间上执行析构函数,完成对象中资源的清理工作2. 调用operator delete函数释放对象的空间
- new T[N]的原理
1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请2. 在申请的空间上执行N次构造函数
- delete[]的原理
1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
💻常见面试题
malloc/free和new/delete的区别
- 1. malloc和free是函数,new和delete是操作符
- 2. malloc申请的空间不会初始化,new可以初始化
- 3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可,
- 如果是多个对象,[]中指定对象个数即可
- 4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
- 5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
特性 + 用法(上面5点)
- 6. 申请自定义类型对象时,malloc / free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
别心急,任何事