news 2026/4/25 11:26:04

C/C++内存管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C/C++内存管理

在 C/C++ 编程中,内存管理是一个核心知识点,直接影响程序的性能和稳定性。本文将详细介绍 C/C++ 中的内存分布、动态内存管理方式及相关原理,帮助大家系统掌握这部分知识。

一、C/C++ 内存分布

程序运行时,内存主要分为以下几个区域:

  1. 栈(堆栈):存储非静态局部变量、函数参数、返回值等,栈是向下增长的。
  2. 内存映射段:高效的 I/O 映射方式,用于装载共享动态内存库,也可用于进程间通信(了解即可)。
  3. :用于程序运行时动态内存分配,堆是向上增长的。
  4. 数据段:存储全局数据和静态数据。
  5. 代码段:存储可执行的代码和只读常量。

内存分布示例分析:

  • char char2[] = "abcd"char2数组在栈上,"abcd" 作为字符串常量在代码段,初始化时会将字符串内容拷贝到栈上的数组中。
  • char* pChar3 = "abcd":指针pChar3在栈上,其指向的字符串常量 "abcd" 在代码段。
  • int* ptr1 = new int[10]:指针ptr1在栈上,其指向的动态内存空间在堆上。

二、C 语言动态内存管理方式

C 语言通过malloccallocreallocfree四个函数进行动态内存管理,它们的区别和特性如下:

函数功能描述初始化特性使用方法
malloc从堆区开辟指定字节数的连续空间不初始化,空间内是随机值void* malloc (size_t size);
calloc从堆区开辟 n 个 “指定大小” 的连续空间(可看作malloc+初始化自动将空间全部初始化为 0void* calloc (size_t num, size_t size);
realloc调整已开辟的堆空间大小(支持扩容 / 缩容扩容时保留原数据,新空间未初始化;缩容时截断数据void* realloc (void* ptr, size_t size);

注意事项:

使用realloc调整空间大小时,若扩容成功,原指针p会被新指针接管,无需单独free(p),只需释放新指针即可。例如:

void Test() { int* p2 = (int*)calloc(4, sizeof(int)); int* p3 = (int*)realloc(p2, sizeof(int) * 10); // 无需free(p2),只需释放p3 free(p3); }

三、C++ 内存管理方式

C 语言的内存管理方式在 C++ 中仍可使用,但 C++ 新增了newdelete操作符,更适合处理自定义类型,使用更简洁。

1. 操作内置类型

  • 申请单个元素空间:new+ 类型,释放用delete
  • 申请连续空间:new[]+ 类型,释放用delete[](必须匹配使用)。
  • 支持初始化,未指定的元素默认置 0。

示例代码:

void Test() { // 动态申请int空间,不初始化 int* p1 = new int; // 动态申请int空间,初始化为10 int* p2 = new int(10); // 动态申请3个int的连续空间,不初始化 int* p3 = new int[3]; // 动态申请10个int的连续空间,全部初始化为0 int* p4 = new int[10] {0}; // 前5个初始化,后5个默认置0 int* p5 = new int[10] {1, 2, 3, 4, 5}; // 释放空间(必须匹配) delete p1; delete p2; delete[] p3; delete[] p4; delete[] p5; }

2. 操作自定义类型

new/deletemalloc/free的核心区别:对自定义类型,new会调用构造函数初始化,delete会调用析构函数清理资源

示例代码:

class A { public: A(int a1 = 0, int a2 = 0) : _a1(a1), _a2(a2) { cout << "A():" << endl; } ~A() { cout << "~A():" << endl; } private: int _a1, _a2; }; int main() { A* p1 = new A(1); // 调用构造函数 A* p2 = new A[3]{A(1,1), A(2,2), A(3,3)}; // 调用3次构造函数 delete p1; // 调用析构函数 delete[] p2; // 调用3次析构函数 return 0; }

四、operator new 与 operator delete 函数

  • newdelete是操作符,底层通过全局函数operator newoperator delete实现内存申请与释放。
  • operator new:内部通过malloc申请空间,失败时抛异常(而非返回 NULL)。
  • operator delete:内部通过free释放空间。

五、new 和 delete 的实现原理

1. 内置类型

  • malloc/free功能类似,但new失败时抛异常,malloc返回 NULL;new[]/delete[]用于连续空间,需匹配使用

2. 自定义类型

  • new的原理

    1. 调用operator new申请空间;

    2. 在空间上执行构造函数。

  • delete的原理

    1. 在空间上执行析构函数;

    2. 调用operator delete释放空间。

  • new T[N]的原理

    1. 调用operator new[]申请 N 个对象的空间;

    2. 执行 N 次构造函数。

  • delete[]的原理

    1. 执行 N 次析构函数;

    2. 调用operator delete[]释放空间。

注意对有析构函数的自定义类型数组,delete必须配合[]使用,否则会因释放位置错误导致崩溃。

示例代码:

class A { public: A(int a1 = 0, int a2 = 0) : _a1(a1) , _a2(a2) { cout << "A():" << endl; } A(const A& aa) : _a1(aa._a1) { cout << "A(const A& aa)" << endl; } ~A() { cout << "~A():" << endl; } private: int _a1 = 0; int _a2 = 0; }; class B { private: int _b1 = 0; int _b2 = 0; }; int main() { //int* p1 = new int[10]; //free(p1); //内置类型可以这样写,不涉及析构 //B中没有显示写析构函数 //B* p2 = new B[10]; //申请10 * 8个字节 //delete p2; //A中显示写析构函数了 A* p3 = new A[10]; //申请8 + 10 * 8个字节,前8个字节放的是个数(64位系统),32位就是4+10 * 8个字节 //delete p3; //报错,因为只释放了一部分,一整段空间不能在中间释放 delete[] p3; // 有析构函数的类释放时要在delete后加上[],实际释放的位置要往前偏移8个字节(64位)或4个字节(32位) return 0; }

六、定位 new 表达式(placement-new)

在已分配的原始内存中手动调用构造函数初始化对象,格式:new (place_address) type(initializer-list)

场景:配合内存池使用(内存池分配的空间未初始化,需手动调用构造函数)。

示例:

A* p = (A*)malloc(sizeof(A)); // 仅开辟空间,未初始化 new (p) A(1, 2); // 调用构造函数初始化 p->~A(); // 手动调用析构函数 free(p); // 释放空间

七、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在释放空间前会调用析构函数完成空间中资源的清理释放

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 10:55:01

1小时用MongoDB搭建博客系统原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 快速开发一个基于MongoDB的博客系统原型。功能包括&#xff1a;1. 用户注册登录&#xff1b;2. 文章发布和管理&#xff1b;3. 评论功能&#xff1b;4. 简单的文章分类和搜索。使用…

作者头像 李华
网站建设 2026/4/24 11:32:08

GeoTools vs 传统GIS开发:效率提升300%的秘密

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个性能对比项目&#xff0c;展示GeoTools与传统GIS开发方式的效率差异&#xff1a;1. 相同空间分析功能的实现代码量对比&#xff1b;2. 执行效率测试&#xff1b;3. 内存占用…

作者头像 李华
网站建设 2026/4/23 20:24:32

Kotaemon会员等级权益设计:忠诚度激励

Kotaemon会员等级权益设计&#xff1a;忠诚度激励 在AI对话系统逐渐从“能说话”迈向“能办事”的今天&#xff0c;一个关键问题浮出水面&#xff1a;当越来越多的开发者涌入智能体生态&#xff0c;如何构建一套既能保障服务质量、又能激发社区贡献的可持续机制&#xff1f; …

作者头像 李华
网站建设 2026/4/23 15:58:50

如何用AI和GeoTools快速构建地理信息系统

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 使用GeoTools库开发一个地理信息系统&#xff0c;包含以下功能&#xff1a;1. 读取和解析Shapefile格式的地理数据&#xff1b;2. 实现空间查询功能&#xff0c;如点是否在多边形内…

作者头像 李华
网站建设 2026/4/19 8:13:59

15分钟用Cobalt Strike搭建红队测试原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 设计一个Cobalt Strike快速原型验证工具&#xff0c;能够&#xff1a;1. 自动配置测试环境&#xff08;包括SSL证书、重定向器&#xff09;&#xff1b;2. 生成基础HTTP/HTTPS Beac…

作者头像 李华
网站建设 2026/4/21 18:36:01

Alibaba SAS下载K8S方式

本人初学k8s&#xff0c;尝试在SAS中下载&#xff0c;起初不断调教AI&#xff0c;试图从AI获取下载方式。 然&#xff0c;始终不得正解。 前往k8s官网一看&#xff0c;才得到解决方案。 在 Linux 系统中安装并设置 kubectl | Kubernetes 首先说明&#xff0c;我的SAS是Alib…

作者头像 李华