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

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

C/C++ 内存分布包含全局区、静态区、栈区、堆区及常量区。C 语言使用 malloc/calloc/realloc 管理堆内存,realloc 扩容可能移动地址导致原指针失效。C++ 引入 new/delete 操作符,底层调用 operator new/delete,自动处理构造函数与析构函数。malloc/free 仅分配内存,new/delete 负责对象生命周期。理解两者差异及内存布局对避免泄漏和崩溃至关重要。

灭霸发布于 2026/3/23更新于 2026/5/46 浏览
C/C++ 内存分布与动态管理

C/C++ 内存分布

我们先来看下面的一段代码和相关问题:

#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";
    // 【指针在栈区】,指向【堆区】通过 malloc 分配的内存
    int* ptr1 = (int*)malloc(sizeof(int)*4);
    // 【指针在栈区】,指向【堆区】通过 calloc 分配并初始化的内存
    int* ptr2 = (int*)calloc(,());
    
    * ptr3 = (*)(ptr2,()*);
    
    (ptr1);
    (ptr3);
}
4
sizeof
int
// 【指针在栈区】,将 ptr2 原有的【堆区】内存进行扩充/移动
int
int
realloc
sizeof
int
4
// 手动释放【堆区】内存
free
free

C 语言的动态内存管理

C 动态内存管理的面试考点

1)realloc 的工作机制
void Test(){
    int* p2 = (int*)calloc(4,sizeof(int));
    int* p3 = (int*)realloc(p2,sizeof(int)*10);
    free(p3);
}
  • 这里需要 free(p2) 吗
  • 不需要。甚至绝对不能这样做

原因在于 realloc 的工作机制:如果 realloc 成功扩容,它会返回一个新的内存地址(可能是原地址,也可能是搬迁后的新地址)。如果返回了新地址,原内存块(p2)会自动被释放。如果你手动执行 free(p2),会导致'重复释放'(Double Free)的错误,这通常会引起程序崩溃。

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

C++ 动态内存管理

  • C 语言内存管理方式在 C++ 中可以继续使用
  • C++ 又提出了自己的内存管理方式:通过 new 和 delete 操作符进行动态内存管理

1)操作内置类型

在 C++ 中,内置类型(如 int, double, char 等)的动态内存分配主要通过 new 和 delete 运算符来实现。

1.1)单个变量的分配和释放
  • 分配: new 类型 或 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;
}
1.2)一维数组的分配与释放

处理数组时,需要使用方括号 []。

  • 分配: new 类型 [元素个数]
  • 释放: delete[] 指针变量 (注意:释放数组必须加 [],否则会导致未定义行为或内存泄漏)
void manageArray(){
    int size = 5;
    // 分配一个长度为 5 的 int 数组
    int* arr = new int[size];
    // 初始化数组(C++11 之后也可以使用 new int[5]{1, 2, 3, 4, 5})
    for(int i = 0; i < size;++i){
        arr[i] = i * 10;
    }
    // 释放数组内存
    delete[] arr;
}

2)操作自定义类型

对于自定义类型(如 struct 或 class),C++ 的 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(){
    A* p1 = (A*)operator new(sizeof(A));
    A* p2 = new A(1);
    operator delete(p1);
    delete p2;
    
    int* p3 = (int*)operator new(sizeof(int));
    int* p4 = new int;
    operator delete(p3);
    delete p4;
    
    A* p5 = (A*)operator new(sizeof(A)*10);
    A* p6 = new A[10];
    operator delete[](p5);
    delete[] p6;
    return 0;
}

3)operator new 与 operator delete 函数

  • new 和 delete 是用户进行动态内存申请和释放的操作符,operator new 和 operator delete 是系统提供的全局函数。

  • new 在底层调用 operator new 全局函数来申请空间,delete 在底层通过 operator delete 全局函数来释放空间。

  • new 表达式 (new expression): 这是我们在代码中常用的 Type* p = new Type();。它是一个'全自动'过程,做了两件事:

    1. 调用 operator new 分配原始内存。
    2. 调用构造函数初始化对象。
  • operator new (函数): 这是一个类似于 malloc 的函数,它的唯一任务是分配一块指定大小的原始内存,不负责构造对象。

3.1)operator new 详解
  • 原型:
void* operator new(size_t size);
  • 工作原理
    • 参数: size 是需要分配的字节数(编译器会自动计算对象大小并传入)。
    • 返回值: 返回指向分配的内存起始地址的 void* 指针。
    • 失败处理: 默认情况下,如果分配失败,它不会返回 nullptr,而是抛出 std::bad_alloc 异常。
    • 自定义行为: 你可以重载全局或类特定的 operator new 来实现自己的内存池或审计逻辑。
3.2)operator delete 详解
  • 原型:
void operator delete(void* ptr) noexcept;
  • 工作原理
    • 对应关系:delete 表达式会先调用对象的析构函数,然后调用 operator delete 来释放内存。
    • 安全性:根据 C++ 标准,向 operator delete 传递 nullptr 是安全的,函数会直接返回而不执行任何操作。
    • 释放逻辑:在底层,它通常封装了 free() 或者系统底层的内存回收接口。

在 C++ 中,noexcept 是一个异常说明,它告诉编译器和程序员:这个函数保证不会抛出异常。

通过上述两个全局函数的实现知道,operator new 实际也是通过 malloc 来申请空间,如果 malloc 申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过 free 来释放空间的。

4)new 和 delete 的实现原理

4.1)内置类型

如果申请的是内置类型的空间,new 和 malloc,delete 和 free 基本类似,不同的地方是: new/delete 申请和释放的是单个元素的空间,new[] 和 delete[] 申请的是连续空间,而且 new 在申请空间失败时会抛异常,malloc 会返回 NULL。

4.2)自定义类型
  • new 的原理
    1. 调用 operator new 函数申请空间
    2. 在申请的空间上执行构造函数,完成对象的构造
  • delete 的原理
    1. 在空间上执行析构函数,完成对象中资源的清理工作
    2. 调用 operator delete 函数释放对象的空间
  • new T[N] 的原理
    1. 调用 operator new[] 函数,在 operator new[] 中实际调用 operator new 函数完成 N 个对象空间的申请
    2. 在申请的空间上执行 N 次构造函数
  • delete[] 的原理
    1. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理
    2. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用 operator delete 来释放空间

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

目录

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

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

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

更多推荐文章

查看全部
  • Text Generation WebUI 模型加载器(Model Loaders)选项详解
  • Python 数据统计指南:从环境配置到高级分析
  • Spring Cloud 商品服务核心实现:库存、缓存与分布式锁
  • Git-AI:实现 AI 生成代码归属追踪的 Git 扩展工具
  • 数据结构与算法:链表分类详解与双向链表初始化实现
  • 数据结构:二叉树基础与 C 语言实现
  • Web 前端基础:HTML、CSS 与 JavaScript 核心知识梳理
  • 基于管道通信的 Linux 进程池实现详解
  • 家庭机器人落地难点分析:技术、成本与隐私
  • AI 提示词核心方法论:从无效提问到精准输出
  • Spring IoC 与 DI 核心概念及实战用法
  • 树莓派 Pico 双语言开发对比:MicroPython 原型与 C/C++ 性能优化
  • Faster-Whisper 本地部署实现实时语音转文本
  • SpringBoot 集成 Shiro 与 Redis 实现 Session 共享
  • .NET 开源分布式事务解决方案:CAP
  • 基于 LangGraph 构建模块化 Skills 型 AI Agent
  • 星辰 RPA 实现小红书自动发文机器人
  • AI Agent 架构:基础组成模块深度解析
  • 无人机发展简史:从古代传说到现代飞行器设计
  • VS Code 安装 GitHub Copilot 实现 AI 辅助编程

相关免费在线工具

  • 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