C/C++动态内存管理

C语言动态内存分配详解(malloc/calloc/free/realloc)以及常见错误 当我们在计算机上打开一个程序,或者创建一个文件时,计算机需要为其分配一定的内存空间来存储程序代码和数据。内存分配是指计算机系统将可用的内存空间分配给不同的程序或文件,以让它们能够在计算机上运行或存储。内存分配是计算机操作系统中的一项重要工作,它涉及到内存的申请、分配、使用和释放等一系列操作。不同的程序或文件需要的内存空间大小不同,因此内存分配需要按需分配,以充分利用计算机的内存资源。 阅读详情

首先我们看看 c 语言是如何进行动态内存分配的;

c 语言主要是使用malloc / calloc / realloc 来进行内存申请的。

malloc / realloc / calloc三者的共同点与不同点:

共同点
1、都是从堆上进行动态内存分配
2、释放内存都是需要使用free函数来释放
3、三者的返回值都是void*
4、都需要强制类型转换
5、都需要对申请出的空间判空(因为申请内存失败会返回空)

不同点:
1)void *malloc( size_t size );
malloc的参数是用户所需内存空间大小的字节数,不会对申请成功的内存初始化。

malloc 申请空间时并不是需要多少就申请多少,而是会多申请一些空间,1)多申请一个32字节的结构体,里面对申请的空间进行描述,2)在申请的空间前后会各多申请 4 个字节的空间,这就是保护机制,当你操作不当越界了,这 8 个字节的内容会改变,操作系统会检查前后 4 个字节是否改变了,以此判断是否越界了。
在这里插入图片描述
在这里插入图片描述

2)void *calloc( size_t num, size_t size );
calloc的参数:第一个:元素的个数,第二个:单个元素所占字节;会把申请成功的空间初始化为 0

3)void *realloc( void *ptr, size_t size );
realloc的参数:第一个:地址,第二个:字节数

  对于 realloc 的第一个参数:
    如果指向空,那么此时realloc 就和 malloc 是一样的;
    如果不为空,那么就将即将要申请的空间与原空间进行比较。

        如果要申请的空间比原空间小,就将原空间缩小,并返回原空间首地址
        如果要申请的空间比原空间大,那么分两种情况,第一种:新旧空间之差小于原空间大小,直接在原空间进行延伸,并返回原空间的首地址。第二种:新旧空间之差大于原空间的大小,那么直接开辟新空间,并将原空间的数据拷贝到新空间,并返回新空间首地址。在这里插入图片描述



看完了 C 动态内存管理,那么来看看C++的动态内存管理:

首先 C 语言中的动态内存管理方式在 C++ 中仍然可以使用。c++ 中多了 new 这个操作符。
new申请的空间:1、不用强制类型转换;2、不用对申请出来的空间进行判空;3、可以申请时初始化这段空间。

  malloc / new / new[] 和 free / delete / delete[]
对于内置类型:如果没有配合使用,可能不会出现什么问题。
对于自定义类型:
  malloc:只是将空间动态开辟成功,并不会调用构造函数初始化空间。
  free:只是将申请的空间进行释放,并不会调用析构函数清理对象中的资源

  new:先将对象的空间开辟成功,然后调用构造函数完成对象的初始化。
  delete:先调用析构函数将对象中的资源清理,然后释放对象占用的空间
如果对一个内部有资源的自定义类型使用 malloc 开辟内存,此时调用 delete 进行空间的释放,程序就会崩溃。因为 malloc 只负责开辟空间,并不会调用对象的构造函数对其成员变量进行初始化,那么内部的成员变量是没有分配空间的,当我们调用 delete 时,delete会先对对象进行资源清理,但是对象里的资源 malloc 并没有给其分配,所以我们清理的时候是非法的操作。导致程序崩溃。

对于内部有资源的自定义类型,使用 new 开辟的空间使用 free 释放,会造成内存泄漏,因为 free 并不会调用析构函数清理对象的资源,因此会造成资源泄漏。

new底层的流程:
第一步:调用operator new() 来申请空间
第二步:调用该类的构造函数

operator new() 的工作流程:
比如 new T:底层调用 void* operator new(sizeof(T)),申请 T 类型大小的堆空间。
  在这个函数中是循环调用 malloc :1、申请空间成功:返回空间的首地址。
                 2、申请空间失败:检测用户是否提供空间不足的应对措施?如果提供应对措施,则执行应对措施,否则直接抛出 bad_alloc 类型的异常。
在这里插入图片描述
new[]的流程:
第一步:调用void* operator new[](count = sizeof(T) * N + 4),如果T类的析构函数显式提供就多申请4个字节。(多申请的四个字节就是用来保存对象的个数,可以知道未来需要调用几次析构函数。)
  这里operator new 的运行流程和上图一致。
第二步:将空间前四个字节填充对象的个数,然后调用构造函数构造 N 个 T 类型对象。

delete的流程:
第一步:调用析构函数清理对象中的资源。
第二步:调用void operator delete(void* p)释放空间,void operator delete(void* p)中调用的是 free 释放空间。
在这里插入图片描述
delete[] 的流程:
第一步:从第一个对象空间之前的4个字节中取对象的个数N
第二步:调用N次析构函数倒着释放(栈的特性)
第三步:void operator delete[](void* p)----这个p就是真正使用位置倒退4个字节的位置,也就是申请的空间的首地址。
在这里operator delete[](void* p) 调用 void operator delete(void* p) 调用 free()

综上:operator new 和 operator delete 实际上是由 malloc 和 free 来实现的,是对malloc 和 free 的封装。


malloc/free 和 new/delete 区别:

共同点:都在堆上申请空间,都需要手动申请 / 释放空间。
不同点:
  1)malloc/free 是函数,new/delete是标识符
  2)malloc 不会对对象进行初始化,new 可以初始化
  3)malloc 申请空间时,需要手动计算需要申请空间的大小,而new只需在后面跟上类型,编译器会自动计算大小。
  4)malloc 返回值是 void*,使用时必须要强制类型转换,而 new 并不需要强制类型转换,因为new后跟的就是类型。
  5)malloc 申请空间失败返回 NULL,因此使用时必须判空,new不需要判空,但是需要捕获异常
  6)申请自定义类型对象时,malloc/free只会开辟空间,并不调用构造/析构函数,而 new 是先申请空间,然后调用构造函数完成对象的初始化,delete 在释放空间前会先清理对象占用的资源
  7)malloc/free 的效率会比 new/delete 的高,因为 new/delete 中封装的是malloc/free。

C/C++语言—动态内存管理 C/C++中程序内存区域划分:  C/C++程序内存区域划分  栈:又叫堆栈,存储非静态局部变量、函数参数、 返回值等,栈是可以向下生长的 内存映射区:是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内 存,做进程间通信 堆:用于程序运行时动态内存分配,堆是可以向上增长的 数据段:存储全局数据和静态数据 代码段:存储可执行的代码、只读常量  C/C... 阅读详情

相关推荐

C/C++动态内存管理malloc/new、free/delete的异同

学习了C和C++之后,我们都知道这两种语言皆有动态内存管理,两者之间异同,我们需要系统的总结一下! 一、相同 两者都可以用来动态申请内存和释放内存; 二、不同 1.malloc/free是C/C++标准库的函数,new/delete是C++操作符。 2.申请内存位置不同 new操作符是从自由存储区上为对象动态分配内存空间的,malloc函数是从堆上动态分配内存。 自...

cherrydreamsover的博客 6484

动态内存分配

(二)用memset和malloc 实现calloc一样的功能。(一)一个c/c++编译的程序占用的内存分为以下几个部分。(一)realloc在调整内存空间的是存在两种情况。对每个从malloc返回的指针都需要进行检查。静态区(全局区)(static)(二)将已经释放的值赋值NULL。(一)free释放内存前后。(四)常见的动态内存错误。内存起始位置(新指针)指针仍然指向这块区域。

m0_63783532的博客 3008

深入详解C/C++动态内存管理

本文详细讲述了C/C++动态内存管理方面的内容,并具体阐述了几类常见的动态内存异常,以供大家借鉴或参考!

dvlinker的技术专栏 2万+

【c语言】—动态内存分配 超详细版本

讲解C语言中的动态内存分配,主讲malloc、calloc和realloc

m0_74044018的博客 5414

避坑指南:Win10安装Docker Desktop时Hyper-V报错的7种解决方案(2024最新版)

本文提供了2024年最新、最全面的Windows 10系统下Docker Desktop安装时Hyper-V报错的解决方案指南。文章深入剖析了Hyper-V与Docker的共生关系,并系统性地给出了从BIOS/UEFI设置、Windows功能启用、bcdedit命令修复到处理多虚拟化环境共存等7种核心解决方案,帮助开发者彻底解决安装困局,顺利部署容器化开发环境。

weixin_28840143的博客 529

nvlddmkm事件ID14报错排查全指南:从找不到描述到显卡驱动崩溃

系统日志中的“无法找到描述”往往让人一头雾水,但这类提示其实隐藏着驱动故障的关键线索。Windows事件查看器通过事件源和ID记录系统异常,其中显卡驱动相关的内核模式驱动组件一旦超时失败,就会触发TDR机制,产生13、14、153等不同事件ID。理解这些ID的含义,比纠结“找不到描述”本身更重要。对于频繁出现的驱动崩溃问题,可以从日志频率和发生场景判断方向,再通过安全模式下彻底清理驱动、关闭冲突软件、检查供电和温度等步骤逐层定位。无论是游戏满载黑屏,还是睡眠唤醒后闪退,掌握NVIDIA驱动日志的解读逻辑,都

weixin_30545945的博客 409

【C/C++】动态内存管理

malloc calloc realloc free 柔性数组

凤年徐的博客 4836

非球面检测

摘要:非球面镜检测主要采用干涉法,包括零位补偿和非零位补偿两种方式。零位补偿通过透镜组完全校正像差,精度达1%波长,但设计复杂成本高;非零位补偿利用部分像差补偿降低波前斜率,适用于规则非球面。折射-衍射混合补偿镜能同时校正多种像差。实际检测中可采用物理补偿镜或动态CGH加载方案,光路设计需运用坐标断点和多重结构技术实现复杂光路建模。不同方法各具优势,需根据检测需求选择合适方案。

Zhaxibamao的博客 2106

C/C++动态内存管理(超详解)

对C和C++11动态内存管理概念,函数,应用场景等的详细介绍

Dai_renwen的博客 2717

若依开源框架(分离版)在人大金仓数据库下使用

对于甲方业务特殊要求,使用国产化数据库人大金仓,作为项目主要存储。这里以若依开源框架整合人大金仓为例,演示如何在真实项目中引入人大金仓。

🐱喵测实验室 5942

如何计算 R 中的基尼系数(附示例)

以意大利统计学家Corrado Gini命名,基尼系数是衡量人口收入分配的一种方法。基尼系数的值在 0 到 1 之间,值越高代表收入不平等越大,其中:0代表完全的收入平等(每个人的收入都一样) 1代表完全的收入不平等(一个人拥有所有收入) 您可以在此处找到按国家/地区列出的基尼系数列表。以下示例显示了使用DescTools包中的Gini()函数计算 R 中的基尼系数的两种方法。示例 1:使用个人收入计算基尼系数假设我们有以下 10 个人的年收入列表:收入:5 万美元、5 万美元、7 万美元、7 万美元、7

Mrrunsen的博客 2990

一文讲懂C/C++动态内存管理

详细介绍C/C++中的动态内存管理

大海洋的博客 1734

[Dify实战] 用 Dify 打造高效的新员工 7 天成长计划-带绑定资源

本文介绍了如何利用Dify平台为新员工制定智能成长计划,解决融入难、节奏乱、成长慢等问题。方案通过输入岗位信息自动生成7天结构化计划,包含每日任务和评估要点,并支持进度跟踪与报告输出。关键点在于设计清晰的Prompt模板,合理分配学习节奏,形成闭环反馈机制。该方案能显著提升新员工培养效率,实现人才培养的数字化升级。

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 569

C/C++ 动态内存管理

跟C语言不同的点在于,C++在new时会调用构造函数,在delete释放空间前会先调用析构函数C++内存申请失败时,会抛异常。

m0_69520125的博客 812

Claude Code 分布式并行开发最佳实践:1中枢+10Worker跨多Git仓库全流程落地

本文介绍了一套基于Claude Code和Git Worktree的分布式并行开发方案,解决多仓库、微服务开发中的核心痛点。方案采用"1个决策中枢+10个并行Worker"架构,中枢负责任务拆解和调度,每个Worker绑定独立仓库实现完全隔离开发。关键优势包括:任务并行效率提升10倍、跨仓库依赖自动编排、版本统一管理、零第三方依赖。文章详细提供了环境准备、架构设计、中枢搭建和初始化脚本等全流程落地指南,特别适合多仓库协同的全栈开发场景。

AI天才研究院 243

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【C语言进阶】那些你必须掌握的C/C++要点——动态内存管理(1)

动态内存管理的要点以及易错点,想学好数据结构必看的内容!!!

君兮_的博客 955

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C/C++的动态内存管理

6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。对于申请的是内置类型的话,new与malloc,delete与free并无太大的区别,不同的地方的是:new和delete申请的是单个元素空间,而new[]和delete[]申请的是连续的空间,而且。4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型。

许我一世白头的博客 776

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

上一篇: C/C++内存布局
下一篇: 编写函数 process_create(pid_t* pid, void* func, void* arg)
coolnut12138
博客等级 码龄9年 51粉丝 75原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值