前言
本节内容将对C与C++的内存管理方面的知识进行分析和解释。
1.C/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); }
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?__C__
staticGlobalVar在哪里?_C___
staticVar在哪里?__C__
localVar在哪里?___A_
num1 在哪里?__A__
char2在哪里?__A__
*char2在哪里?__A_
pChar3在哪里?__A__
*pChar3在哪里?___D
ptr1在哪里?_A___
*ptr1在哪里?__B__
详细的图解如下
【说明】
1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。
2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)
3. 堆用于程序运行时动态内存分配,堆是可以上增长的。
4. 数据段--存储全局数据和静态数据。
5. 代码段--可执行的代码/只读常量。
2.C语言中动态内存管理方式:malloc/calloc/realloc/free (回顾)
void Test () { // 1.malloc/calloc/realloc的区别是什么? int* p2 = (int*)calloc(4, sizeof (int)); int* p3 = (int*)realloc(p2, sizeof(int)*10); // 这里需要free(p2)吗? free(p3 ); }
1. malloc:
- 语法:void* malloc(size_t size);
- 功能:分配指定字节数的内存,但不会初始化内存。分配的内存包含不确定的值。
- 示例:int* p = (int*)malloc(4 * sizeof(int));
2. calloc:
- 语法:void* calloc(size_t num, size_t size);
- 功能:分配内存用于数组,并初始化所有位为0。num`是元素数量,size是每个元素的大小。
- 示例:int* p = (int*)calloc(4, sizeof(int));(分配4个整数并初始化为0)
3. realloc:
- 语法:void* realloc(void* ptr, size_t size);
- 功能:重新调整已分配内存的大小。如果 ptr 是 NULL,效果等同于 malloc;如果 size 为0,用法等同于 `free`。如果扩展内存,原有数据将被保留。
- 示例:int* p = (int*)realloc(p2, sizeof(int) * 10);` 对于你的代码片段:
不用释放p2
- 使用 calloc 分配内存后,p2指向这块内存。 - 当你使用 `realloc` 调整 `p2` 的大小时,`realloc` 会返回一个新的指针 `p3`,如果内存调整成功,原来 `p2` 的内存会被释放,因此你不需要再对 `p2` 调用 `free`。
3.C++内存管理方式
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因
此C++又提出了自己的内存管理方式: 通过 new 和 delete 操作符进行动态内存管理。
3.1new/delete操作内置类型
#include <iostream> using namespace std; int main() { //动态申请一个int类型的空间并初始化为520 int* p1 = new int(520); 动态申请3个int类型的空间并初始化 int* p2 = new int[3] {1, 2, 3}; cout << *p1 << endl; for (int i = 0; i < 3; ++i) { cout << "p2[" << i << "]: " << p2[i] << endl; } // 释放内存 delete p1; delete[] p2; return 0; }
注意事项
- 内存管理:
- 动态分配的内存需要手动释放,以防止内存泄漏。
- 使用
delete
释放单个对象内存,使用delete[]
释放数组内存。
- 初始化方式:
- 在 C++11 及以后,可以使用初始化列表对动态数组进行初始化,如你所示的
{1, 2, 3}
。 - 在较旧的 C++ 版本中,动态数组的初始化可以通过循环来完成,因为不支持在
new
语句中直接初始化数组。
3.2new/delete操作自定义类型
#include <iostream> using namespace std; class A { public: A(int a=0 , int b=0) :_a(a), _b(b) { cout << "A(int a = 0, int b = 0)" << endl; } ~A(){ cout << "~A()" << endl; } //void Print(){ // cout << "A::Print->" << _a << endl; //} private: int _a = 1; int _b = 1; }; int main() { A* p1 = new A(520); A* p2 = new A(520,1314); delete p1; delete p2; //该自定义类型初始化方法 A aa1(1, 1); A aa2(2, 2); A aa3(3, 3); A* p3 = new A[3]{aa1, aa2, aa3}; delete[]p3; //匿名初始化 A* p4 = new A[3]{ A(1,1), A(2,2), A(3,3)}; delete[]p4; //列表初始化 A* p5 = new A[3]{ {1,1}, {2,2}, {3,3} }; delete []p5; return 0; }
注意:在申请自定义类型的空间时, new 会调用构造函数, delete 会调用析构函数,而 malloc 与
free 不会。
C/C++内存管理(下):https://developer.aliyun.com/article/1624948