C/C++内存管理:代码稳健运行的密钥
在C/C++的世界里,内存从来不是“取之不尽、用之不竭”的抽象概念——它是程序运行的“物理舞台”,每一个变量的诞生、每一次函数的调用、每一段数据的流转,都依赖于对这片舞台的精准调度。与那些自带“内存管家”(如垃圾回收机制)的编程语言不同,C/C++将内存的控制权彻底交还给程序员:你可以亲手分配一块内存,决定它的生命周期,也能在不需要时主动释放它。这种“绝对掌控”既是C/C++高效性的根源,也是无数bug的温床。 内存管理的细节往往决定了代码的健壮性与可靠性。 本文将从内存的分配机制入手,拆解堆与栈的本质区别,剖析`malloc/free`与`new/delete`的底层逻辑,更会直面内存管理中最棘手的问题——如何识别泄漏、规避野指针、处理动态数组的边界风险。无论你是刚接触C/C++的新手,还是希望填补知识漏洞的开发者,掌握这些内容,不仅能让你的代码远离隐蔽的内存陷阱,更能理解程序运行的底层逻辑,真正驾驭C/C++赋予的“极致控制力”。
一C/C++中内存区域划分

C/C++中,内存空间分为堆区,栈区,静态区,常量区,按操作系统层面来说,静态区又叫数据段,代码区又叫代码段。
【说明】
1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。
2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口
创建共享共享内存,做进程间通信。(Linux课程如果没学到这块,现在只需要了解一下)
3. 堆用于程序运行时动态内存分配,堆是可以上增长的。
4. 数据段--存储全局数据和静态数据。
5. 代码段--可执行的代码/只读常量。
不同的区域存放的数据是不一样的,看下面这个问题:

二C语言中动态内存管理方式:malloc/calloc/realloc/free
1)malloc


2)realloc


3)calloc


这些我们都很熟悉,只看一个思考题
#include<iostream>
using namespace std;
void test01()
{
int* p1 = (int*)calloc(10, sizeof(int));
int* p2 = (int*)realloc(p1, sizeof(int));
free(p2);
//还要free p1吗?
}
int main()
{
test01();
return 0;
}
解析:realloc函数在调整内存大小时,若成功,会将原内存块(p1 指向的)的管理权限转移到新的内存块(p2 指向的),此时 p1 已经失效。只需释放 p2 即可,若再 free p1 会导致重复释放内存的错误。
4)malloc的实现原理
三C++内存管理方式
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因
此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
1)对内置类型操作
void test02()
{
int* p1 = new int;
//动态申请一个int类型的空间
int* p2 = new int[10];
//动态申请十个int类型的空间,一个数组
//初始化
int* p3 = new int(1);
//动态申请一个int类型的空间,初始化为1
int* p4 = new int[10] {1};
//动态申请十个int类型的空间,初始化为1
//内存释放
delete p1;//单个对象
delete[] p2;//数组
delete p3;
delete p4;
}

2)对自定义类型操作
在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数。
多对象申请空间会多次调用构造函数。
申请多个对象会保存数据个数,来决定调用析构函数的次数(如果有资源需要释放的话)
void test03()
{
//在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数
A* a2 = (A*)malloc(sizeof(A));
free(a2);
A* a1 = new A;
delete a1;
int* b1 = (int*)malloc(sizeof(int));
free(b1);
int* b2 = new int;
delete b2;
A* a3 = (A*)malloc(sizeof(A));
free(a3);
A* a4 = new A[sizeof(A) * 10];
delete []a4;
}
int main()
{
test03();
return 0;
}
四operator new和operator delete函数
new和delete是用户进行动态内存申请和释放的操作符,operatornew和operatordelete是系统提供的全局函数,new在底层调用operatornew全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。

我们只要知道,operator new实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operatordelete最终是通过free来释放空间的。
五new和delete的实现原理
1)内置类型
Lnew/delete和malloc/free基本没区别,申请失败new会抛异常,malloc会返回NUL。
2)自定义类型
new的原理
1.调用operator new函数申请空间
2.在申请的空间上执行构造函数,完成对象的构造
delete的原理
1.在空间上执行析构函数,完成对象中资源的清理工作
2.调用operator delete函数释放对象的空间
newT[N]的原理
1.调用operator new[]函数,在operator ne[]中实际调用operator new函数完成N个对象空间的申请
2.在申请的空间上执行N次构造函数
delete[]的原理
1.在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
2.调用operator delete[释放空间,实际在operator delete[中调用operator delete来释放空间
六malloc/free和new/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需
要捕获异常
6.申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理释放
七定位new(了解)
在 C++ 中,定位 new(placement new) 是一种特殊的 new 操作符形式,它允许在已分配的内存块上构造对象,而不重新申请新的内存。其核心作用是 “利用已有内存空间创建对象”,主要用于内存池、缓存管理等需要精确控制对象构造位置的场景。
#include <new> // 必须包含此头文件
// 在指针 p 指向的内存地址上构造一个 T 类型的对象
new (p) T(构造参数);
更多推荐

所有评论(0)