跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++

C/C++ 内存管理与动态分配核心解析

C/C++ 内存分布涵盖全局区、栈区、堆区等区域。C 语言通过 malloc/calloc/realloc 管理动态内存,需注意 realloc 可能返回新地址导致原指针失效。C++ 引入 new/delete 操作符,自动调用构造函数和析构函数。两者区别在于类型安全、初始化行为及异常处理机制。掌握这些底层机制有助于避免内存泄漏和野指针问题。

追风少年发布于 2026/3/23更新于 2026/5/16 浏览
C/C++ 内存管理与动态分配核心解析

C/C++ 内存分布与动态管理详解

在深入代码之前,我们先理清程序运行时的内存布局。理解这块'地盘'怎么划分,是避免内存泄漏和野指针的前提。

一、C/C++ 内存分布概览

通常我们将内存划分为以下几个主要区域:

  • 栈区 (Stack):存放局部变量、函数参数等。由编译器自动管理,函数结束即释放。
  • 堆区 (Heap):通过 malloc/new 手动申请的空间。生命周期由程序员控制,需手动释放。
  • 全局/静态区:存放全局变量、静态变量。程序启动时分配,结束时释放。
  • 常量区:存放字符串字面量等不可修改数据。
  • 代码区:存放二进制指令。

来看一段典型的代码示例,观察不同变量的存储位置:

#include <stdio.h>
#include <stdlib.h>

// 【全局/静态区】.data:已初始化的全局变量
int globalVar = 1;

// 【全局/静态区】.data:已初始化的静态全局变量
static int staticGlobalVar = 1;

void Test() {
    // 【全局/静态区】.data:已初始化的静态局部变量(生命周期为整个程序)
    static int staticVar = 1;
    
    // 【栈区】:局部变量,函数运行结束自动释放
    int localVar = 1;
    
    // 【栈区】:局部数组
    int num1[10] = {1, 2, 3, 4};
    
    // 【栈区】:字符数组(注意:"abcd" 会被拷贝到栈上)
    char char2[] = "abcd";
    
    // 【指针在栈区】,但指向的 "abcd" 字符串字面量在【常量区/代码段】
    const char* pChar3 = "abcd";
    
    
    * ptr1 = (*)(() * );
    
    
    * ptr2 = (*)(, ());
    
    
    * ptr3 = (*)(ptr2, () * );
    
    
    (ptr1);
    (ptr3);
}
// 【指针在栈区】,指向【堆区】通过 malloc 分配的内存
int
int
malloc
sizeof
int
4
// 【指针在栈区】,指向【堆区】通过 calloc 分配并初始化的内存
int
int
calloc
4
sizeof
int
// 【指针在栈区】,将 ptr2 原有的【堆区】内存进行扩充/移动
int
int
realloc
sizeof
int
4
// 手动释放【堆区】内存
free
free

内存分布示意图

内存区域详解

二、C 语言的动态内存管理

C 语言提供了四个标准库函数来处理堆内存:malloc、calloc、realloc 和 free。

1. realloc 的工作机制

在使用 realloc 扩容或缩容时,有一个常见的陷阱需要注意。

void Test() {
    int* p2 = (int*)calloc(4, sizeof(int));
    int* p3 = (int*)realloc(p2, sizeof(int) * 10);
    free(p3); // 只需释放返回的新指针
}

这里需要 free(p2) 吗? 不需要,甚至绝对不能这样做。

原因在于 realloc 的内部逻辑:如果内存足够且无需搬迁,它可能直接返回原地址;如果需要搬迁,它会分配新空间,复制数据,然后释放旧空间,最后返回新地址。无论哪种情况,原指针 p2 要么失效,要么已被内部释放。如果你手动执行 free(p2),会导致'重复释放'(Double Free),这通常会引发程序崩溃。

2. malloc / calloc / realloc 的区别

函数功能描述初始化行为参数形式
malloc分配指定字节大小的内存不初始化,内容为随机垃圾值malloc(size_t size)
calloc分配 n 个元素的内存自动初始化为 0calloc(n, size)
realloc调整已分配内存块的大小不对新增空间进行初始化realloc(ptr, new_size)

三、C++ 的动态内存管理

C++ 继承了 C 的内存管理方式,同时引入了更高级的操作符 new 和 delete。

1. 操作内置类型

对于 int、double 等内置类型,new 和 delete 的使用相对直观。

单个变量的分配和释放
int main() {
    // 1. 分配一个未初始化的 int
    int* p1 = new int;
    
    // 2. 分配并初始化为 100
    int* p2 = new int(100);
    
    // 使用完毕后必须释放内存
    delete p1;
    delete p2;
    
    // 良好的习惯:将指针置为空,防止野指针
    p1 = nullptr;
    p2 = nullptr;
    return 0;
}
一维数组的分配与释放

处理数组时,必须使用方括号 [] 来匹配构造和析构过程。

void manageArray() {
    int size = 5;
    // 分配一个长度为 5 的 int 数组
    int* arr = new int[size];
    
    // 初始化数组
    for (int i = 0; i < size; ++i) {
        arr[i] = i * 10;
    }
    
    // 释放数组内存,注意必须加 []
    delete[] arr;
}

2. 操作自定义类型

这是 C++ 内存管理的核心差异点。对于 struct 或 class,new 和 delete 不仅分配内存,还负责调用构造函数和析构函数。

#include <iostream>
using namespace std;

class A {
public:
    A(int a = 0) : _a(a) { cout << "A():" << this << endl; }
    ~A() { cout << "~A():" << this << endl; }
private:
    int _a;
};

int main() {
    // 仅调用 operator new,不调用构造函数
    A* p1 = (A*)operator new(sizeof(A));
    // 调用 operator new + 构造函数
    A* p2 = new A(1);
    
    // 仅调用 operator delete,不调用析构函数
    operator delete(p1);
    // 调用析构函数 + operator delete
    delete p2;
    
    return 0;
}

3. operator new 与 operator delete 函数

  • new 和 delete 是用户使用的操作符。
  • operator new 和 operator delete 是系统提供的全局函数。

new 表达式 (new expression):这是一个'全自动'过程,包含两步:

  1. 调用 operator new 分配原始内存。
  2. 调用构造函数初始化对象。

operator new (函数):类似于 malloc,唯一任务是分配指定大小的原始内存,不负责构造对象。

operator new 详解
  • 原型: void* operator new(size_t size);
  • 失败处理: 默认情况下,如果分配失败,它不会返回 nullptr,而是抛出 std::bad_alloc 异常。
  • 自定义行为: 你可以重载该函数来实现自己的内存池或审计逻辑。
operator delete 详解
  • 原型: void operator delete(void* ptr) noexcept;
  • 安全性: 向 operator delete 传递 nullptr 是安全的,函数会直接返回。
  • 底层实现: 通常封装了 free() 或者系统底层的内存回收接口。

注:noexcept 说明该函数保证不会抛出异常。

4. new 和 delete 的实现原理

内置类型

new/delete 与 malloc/free 基本类似。区别在于:

  • new/delete 申请的是单个元素空间,new[]/delete[] 申请连续空间。
  • new 失败抛异常,malloc 返回 NULL。
自定义类型
  • new 的原理:
    1. 调用 operator new 函数申请空间。
    2. 在申请的空间上执行构造函数,完成对象的构造。
  • delete 的原理:
    1. 在空间上执行析构函数,完成对象中资源的清理工作。
    2. 调用 operator delete 函数释放对象的空间。

5. malloc/free 和 new/delete 的区别

虽然两者都从堆上申请空间,但存在本质差异:

  1. 性质不同:malloc/free 是函数,new/delete 是操作符。
  2. 初始化:malloc 不初始化,new 可以初始化(内置类型)或调用构造函数(自定义类型)。
  3. 语法便捷性:malloc 需手动计算大小,new 后跟类型即可。
  4. 返回值:malloc 返回 void* 需强转,new 返回具体类型指针。
  5. 错误处理:malloc 失败返回 NULL,需判空;new 失败抛异常,需捕获。
  6. 对象生命周期:malloc/free 只管理内存,不管理对象构造/析构;new/delete 全权负责。

掌握这些底层机制,能帮助你在编写高性能 C/C++ 代码时做出更合适的选择,有效规避内存风险。

目录

  1. C/C++ 内存分布与动态管理详解
  2. 一、C/C++ 内存分布概览
  3. 二、C 语言的动态内存管理
  4. 1. realloc 的工作机制
  5. 2. malloc / calloc / realloc 的区别
  6. 三、C++ 的动态内存管理
  7. 1. 操作内置类型
  8. 单个变量的分配和释放
  9. 一维数组的分配与释放
  10. 2. 操作自定义类型
  11. 3. operator new 与 operator delete 函数
  12. operator new 详解
  13. operator delete 详解
  14. 4. new 和 delete 的实现原理
  15. 内置类型
  16. 自定义类型
  17. 5. malloc/free 和 new/delete 的区别
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Web1.0 到 Web3.0:互联网三次进化解析
  • Spring Boot 数据仓库与 ETL 工具集成实践
  • 腾讯混元图像 3.0 图生图模型开源,LMArena 评测跻身全球第一梯队
  • Python 自动化实战:wxauto 安装异常处理与核心功能详解
  • 代码大模型浪潮下,IT 技术人员的应对与转型策略
  • JavaScript 基础语法与核心概念详解
  • 前端实现视频画中画功能 - 主页面与小窗同步控制
  • 自然语言处理高级应用与前沿发展
  • Windows Python 安装与配置教程
  • Electron 桌面应用打包实战:builder 与 packager 深度解析
  • Soft Actor-Critic (SAC) 算法详解与 PyTorch 实现
  • 开源 AI 编程工具选型对比:OpenCode 与 GitHub Copilot 优劣分析
  • 基于 JsPDF 和 html2canvas 实现前端图表与列表数据多格式导出
  • C++ 仿函数详解:对象像函数一样调用
  • 自然语言处理在教育领域的应用与实战
  • FastGPT 结合 MCP 协议实现工具增强型智能体构建
  • VS Code 新版禁用 Ctrl+I 快捷键唤起 Copilot AI 对话框
  • 前端小白必看 React Router路由配置全攻略(附避坑指南)
  • 雷达信号处理中的恒虚警率(CFAR)技术详解
  • 分布式文件系统 HDFS 存储原理

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online