尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

C/C++内存管理

C/C++内存管理
📅 发布时间:2026/6/18 14:15:26

在 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 语言通过malloc、calloc、realloc和free四个函数进行动态内存管理,它们的区别和特性如下:

函数功能描述初始化特性使用方法
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++ 新增了new和delete操作符,更适合处理自定义类型,使用更简洁。

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/delete与malloc/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 函数

  • new和delete是操作符,底层通过全局函数operator new和operator 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在释放空间前会调用析构函数完成空间中资源的清理释放

相关新闻

  • AI应用架构师干货:虚拟工作系统的AI能力评估指标与架构优化方法论
  • PathOfBuilding使用指南:从Build规划新手到专家的系统性转变
  • Kotaemon模型量化技巧:INT8/FP16压缩部署

最新新闻

  • PiliPlus完全指南:打造你的专属B站开源客户端
  • 基于六维超混沌与DNA编码的图像加密算法实现与解析
  • 再生资源行业实力测评 海峰梦再生资源口碑价格透明推荐 - 工业品牌热点
  • 如何快速构建智能标注系统:OpenMMLab MMPose的完整指南
  • vscode-edge-devtools 设备模拟功能详解:响应式设计调试技巧
  • Loop:优雅掌控macOS窗口管理的终极解决方案

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号