new/delete和malloc/free到底有什么区别

server/2024/9/22 20:27:48/
cle class="baidu_pl">
cle_content" class="article_content clearfix">
content_views" class="markdown_views prism-tomorrow-night">cap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

c_0">new和malloc

class="toc">

文章目录

  • new和malloc
  • 前言
  • 一、属性上的区别
  • 二、使用上的区别
  • 三、内存位置的区别
  • 四、返回类型的区别
  • 五、分配失败的区别
  • 六、扩张内存的区别
  • 七、系统调度过程的区别
  • 总结


前言

new和malloc的知识点࿰c;作为一个嵌入式工程师是必须要了解清楚的。new和malloc的区别到底在哪里呢

内存分配通常在以下场景下使用:

动态数据结构:如链表、栈、队列和图࿰c;这些数据结构的大小在程序运行时可能会变化。
大数据处理:当需要处理大块数据(如图像、文件数据等)时࿰c;动态分配可以根据实际需求分配内存。
用户输入:当用户输入的内容大小不可预见时࿰c;如读取不定长度的字符串。
资源管理:在需要创建大量对象࿰c;但具体数量在编译时无法确定的情况࿰c;如对象池或缓存系统。
动态内存分配提供了灵活性࿰c;使程序能够有效地管理内存࿰c;根据实际需求分配和释放内存。

一、属性上的区别

new/delete:是C++中的关键字(操作符)࿰c;若要使用࿰c;需要编译器支持;
malloc/free:是标准库函数࿰c;若要使用则需要引入相应的头文件才可以正常使用。

二、使用上的区别

malloc:申请空间需要显式填入申请内存的大小;
new:无需显式填入申请的内存大小࿰c;new会根据new的类型分配内存。

<code class="prism language-c">class="token comment">/** malloc/free **/
class="token keyword">int  class="token operator">*a  class="token operator">= class="token punctuation">(class="token keyword">intclass="token operator">*class="token punctuation">) class="token function">mallocclass="token punctuation">(class="token number">4class="token punctuation">)class="token function">freeclass="token punctuation">(aclass="token punctuation">)code>

在这里࿰c;malloc(4) 分配了 4 字节的内存。由于 int 类型通常占用 4 字节࿰c;因此分配了足够存储一个 int 类型的数据。free 函数用于释放之前通过 malloc 或其他动态内存分配函数分配的内存。在这里࿰c;free(a) 释放了指针 a 指向的 4 字节的内存块。

<code class="prism language-c">class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><stdio.h>
class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><stdlib.h>class="token keyword">int class="token function">mainclass="token punctuation">(class="token punctuation">) class="token punctuation">{class="token comment">// 动态分配内存以存储一个整数class="token keyword">int class="token operator">*a class="token operator">= class="token punctuation">(class="token keyword">intclass="token operator">*class="token punctuation">) class="token function">mallocclass="token punctuation">(class="token keyword">sizeofclass="token punctuation">(class="token keyword">intclass="token punctuation">)class="token punctuation">)class="token punctuation">;class="token comment">// 检查内存分配是否成功class="token keyword">if class="token punctuation">(a class="token operator">== class="token constant">NULLclass="token punctuation">) class="token punctuation">{class="token function">printfclass="token punctuation">(class="token string">"内存分配失败\n"class="token punctuation">)class="token punctuation">;class="token keyword">return class="token number">1class="token punctuation">; class="token comment">// 结束程序并返回错误代码class="token punctuation">}class="token comment">// 设置分配的内存中的值class="token operator">*a class="token operator">= class="token number">42class="token punctuation">;class="token comment">// 打印内存中的值class="token function">printfclass="token punctuation">(class="token string">"内存中的值是: %d\n"class="token punctuation">, class="token operator">*aclass="token punctuation">)class="token punctuation">;class="token comment">// 释放分配的内存class="token function">freeclass="token punctuation">(aclass="token punctuation">)class="token punctuation">;class="token comment">// 将指针设为 NULL࿰c;避免悬挂指针a class="token operator">= class="token constant">NULLclass="token punctuation">;class="token keyword">return class="token number">0class="token punctuation">;
class="token punctuation">}code>

c="https://i-blog.csdnimg.cn/direct/88be240343b44bbd89530b34506262dc.png" alt="在这里插入图片描述" />
在调用 free 函数之前࿰c;确保指针确实指向了动态分配的内存是非常重要的。
为什么需要确保指针指向动态分配的内存?
1.内存释放的正确性:
free 函数的作用是释放之前由 malloccalloc 或 realloc 函数分配的内存。如果指针 a 不指向有效的动态分配内存区域(即没有通过这些函数分配的内存)࿰c;调用 free(a) 可能会导致未定义行为。未定义行为可能会导致程序崩溃、内存泄漏、数据损坏或其他难以预测的错误。
2.内存管理的安全性:
如果 a 指向非动态分配的内存(比如一个局部变量、全局变量或者静态变量)࿰c;调用 free 可能会导致操作系统试图释放不属于它的内存࿰c;造成错误。例如࿰c;如果你试图释放一个未分配的指针或者已经被释放的指针(悬挂指针)࿰c;这也会导致问题。
确保指针指向动态内存的措施
1.初始化指针:
在使用指针之前࿰c;初始化它为 NULL。这样࿰c;如果你忘记分配内存࿰c;它至少不会指向一个不确定的位置。
例如:int *a = NULL;
分配内存之后检查指针:
每次调用 malloc 或相关函数后࿰c;都应该检查指针是否为 NULL。如果为 NULL࿰c;说明内存分配失2.败࿰c;需要处理这种情况。
2.避免重复释放
确保每个动态分配的内存块只被释放一次。重复释放同一块内存会导致未定义行为。
在释放内存后࿰c;可以将指针设置为 NULL࿰c;这有助于避免对已经释放内存的重复释放尝试。

<code class="prism language-c">class="token function">freeclass="token punctuation">(aclass="token punctuation">)class="token punctuation">;
a class="token operator">= class="token constant">NULLclass="token punctuation">;
code>

3.管理指针的生命周期:
确保在释放内存之前࿰c;所有指针操作都合法且在范围内。避免在释放内存后还尝试使用该内存(如访问已释放的内存)。

<code class="prism language-c"> class="token comment">// 尝试释放已经释放的指针࿰c;安全地检查class="token keyword">if class="token punctuation">(a class="token operator">!= class="token constant">NULLclass="token punctuation">) class="token punctuation">{class="token function">freeclass="token punctuation">(aclass="token punctuation">)class="token punctuation">; class="token comment">// 这行不会被执行࿰c;因为 ma 是 NULLclass="token punctuation">}
code>
<code class="prism language-c">class="token comment">/** new/delete **/
class="token keyword">int class="token operator">*b class="token operator">= new class="token keyword">intclass="token punctuation">(class="token number">0class="token punctuation">)class="token punctuation">;
code>

分配内存:使用 new 关键字在堆上分配内存来存储一个 int 类型的值。
初始化内存:将这个 int 初始化为 0。
返回指针:new 操作符返回一个指向这块内存的指针࿰c;该指针被赋值给 b。
因此࿰c;b 是一个指向 int 类型的指针࿰c;指向的内存位置存储着值 0。

<code class="prism language-c">class="token macro property">class="token directive-hash">#class="token directive keyword">include class="token string"><iostream>class="token keyword">int class="token function">mainclass="token punctuation">(class="token punctuation">) class="token punctuation">{class="token comment">// 使用 new 操作符分配内存并初始化为 0class="token keyword">int class="token operator">*b class="token operator">= new class="token keyword">intclass="token punctuation">(class="token number">0class="token punctuation">)class="token punctuation">;class="token comment">// 输出指针 b 指向的值stdclass="token operator">::cout class="token operator"><< class="token string">"The value of *b is: " class="token operator"><< class="token operator">*b class="token operator"><< stdclass="token operator">::endlclass="token punctuation">;class="token comment">// 修改 b 指向的值class="token operator">*b class="token operator">= class="token number">42class="token punctuation">;stdclass="token operator">::cout class="token operator"><< class="token string">"The new value of *b is: " class="token operator"><< class="token operator">*b class="token operator"><< stdclass="token operator">::endlclass="token punctuation">;class="token comment">// 释放分配的内存 避免内存泄漏delete bclass="token punctuation">;class="token comment">// 将 b 设置为 nullptr࿰c;以避免悬挂指针b class="token operator">= nullptrclass="token punctuation">;class="token keyword">return class="token number">0class="token punctuation">;
class="token punctuation">}code>

c="https://i-blog.csdnimg.cn/direct/a79373b720e4455a9dc41a6719925096.png" alt="在这里插入图片描述" />

三、内存位置的区别

new:此操作符分配的内存空间是在自由存储区;
malloc:申请的内存是在堆空间。
C/C++的内存通常分为:堆、栈、自由存储区、全局/静态存储区、常量存储区。可能除了自由存储区࿰c;其他的内存分布大家应该都比较熟悉。堆:是C语言和操作系统的术语࿰c;堆是操作系统所维护的一块特殊内存࿰c;它提供了动态分配的功能࿰c;当运行程序调用malloc()时就会从中分配࿰c;调用free()归还内存。自由存储区:是C++中动态分配和释放对象的一个概念࿰c;通过new分配的内存区域可以称为自由存储区࿰c;通过delete释放归还内存。自由存储区可以是堆、全局/静态存储区等࿰c;具体是在哪个区࿰c;主要还是要看new的实现以及C++编译器默认new申请的内存是在哪里。但是基本上࿰c;很多C++编译器默认使用堆来实现自由存储࿰c;运算符new和delete内部默认是使用malloc和free的方式来被实现࿰c;说它在堆上也对࿰c;说它在自由存储区上也正确。因为在C++中new和delete符号是可以重载的࿰c;我们可以重新实现new的实现代码࿰c;可以让其分配的内存位置在静态存储区等。而malloc和free是C里的库函数࿰c;无法对其进行重载。

四、返回类型的区别

new操作符内存分配成功时࿰c;返回的是对象类型的指针࿰c;类型严格与对象匹配࿰c;无须进行类型转换࿰c;故new是符合类型安全性的操作符。
malloc内存分配成功则是返回void* ࿰c;需要通过强制类型转换将void*指针转换成我们需要的类型。所以在C++程序中使用new会比malloc安全可靠。

五、分配失败的区别

malloc分配内存失败时返回NULL࿰c;我们可以通过判断返回值可以得知是否分配成功;
new内存分配失败时࿰c;会抛出bac_alloc异常࿰c;它不会返回NULL࿰c;分配失败时如果不捕捉异常࿰c;那么程序就会异常退出。

六、扩张内存的区别

malloc:使用malloc分配内存后࿰c;发现内存不够用࿰c;那我们可以通过realloc函数来扩张内存大小࿰c;realloc会先判断当前申请的内存后面是否还有足够的内存空间进行扩张࿰c;如果有足够的空间࿰c;那么就会往后面继续申请空间࿰c;并返回原来的地址指针;否则realloc会在另外有足够大小的内存申请一块空间࿰c;并将当前内存空间里的内容拷贝到新的内存空间里࿰c;最后返回新的地址指针。
new:new没有扩张内存的机制。

七、系统调度过程的区别

malloc free是库函数而不是运算符࿰c;不在编译器控制范围之内࿰c;不能够自动调用构造函数和析构函数。NEW在为对象申请分配内存空间时࿰c;可以自动调用构造函数࿰c;同时也可以完成对对象的初始化。同理࿰c;delete也可以自动调用析构函数。而malloc只是做一件事࿰c;只是为变量分配了内存࿰c;同理࿰c;free也只是释放变量的内存。

总结

new:

<code class="prism language-c">class="token keyword">int class="token operator">*p class="token operator">= new class="token keyword">intclass="token punctuation">(class="token number">5class="token punctuation">)class="token punctuation">; class="token comment">// 分配内存并初始化为 5
code>

在 C++ 中使用。
会调用构造函数来初始化对象。
用于分配单个对象或数组。
malloc

<code class="prism language-c">class="token keyword">int class="token operator">*p class="token operator">= class="token punctuation">(class="token keyword">intclass="token operator">*class="token punctuation">)class="token function">mallocclass="token punctuation">(class="token keyword">sizeofclass="token punctuation">(class="token keyword">intclass="token punctuation">)class="token punctuation">)class="token punctuation">; class="token comment">// 分配内存࿰c;但不初始化
code>

在 C 和 C++ 中使用。
不会调用构造函数࿰c;内存中的内容是未定义的。
需要强制转换为目标类型。

  1. 内存释放
    new:使用 delete 或 delete[] 来释放内存。
<code class="prism language-c">delete pclass="token punctuation">;       class="token comment">// 对应单个对象
deleteclass="token punctuation">[class="token punctuation">] pclass="token punctuation">;     class="token comment">// 对应对象数组
code>

malloc:使用 free 来释放内存。

<code class="prism language-c">class="token function">freeclass="token punctuation">(pclass="token punctuation">)class="token punctuation">;
code>
  1. 异常处理
    new:
    如果内存分配失败࿰c;new 会抛出 std::bad_alloc 异常。
    可以使用 new(std::nothrow) 来避免抛出异常࿰c;而是返回 nullptr。
    malloc
    如果内存分配失败࿰c;malloc 返回 NULL。不会抛出异常࿰c;适用于不支持 C++ 异常的环境。
  2. 适用场景
    new:
    适用于 C++ 编程࿰c;特别是当你需要初始化对象或管理对象生命周期时。
    与 C++ 的对象构造和析构机制兼容。
    malloc
    适用于 C 或者 C++ 中的低级内存管理࿰c;尤其是当你在 C++ 环境中需要兼容 C 代码时。
    更适合需要原始内存块的场景࿰c;但需要手动处理初始化和类型转换。

http://www.ppmy.cn/server/118397.html

相关文章

React项目中使用发布订阅模式

React项目中使用发布订阅模式 1.创建发布订阅器2.在组件中使用发布订阅器3. 订阅数据 发布订阅模式&#xff08;也称观察者模式&#xff09;是一种管理跨组件通信的有效方式&#xff0c;尤其是在不希望直接依赖于特定组件的情况下。这种模式允许一个对象&#xff08;发布者&…

vivado中选中bd文件后generate output product是什么用,create HDL wrapper是什么用

vivado中选中bd文件后generate output product是什么用 在Vivado中&#xff0c;“Generate Output Products” 是一个重要的步骤&#xff0c;它用于生成IP核的输出产品&#xff0c;这些产品是将IP核集成到设计中所需的文件。这些输出产品包括&#xff1a; 综合文件&#xff…

HarmonyOS学习(十)——网络编程

文章目录 1、通过HTTP请求网络2、Web组件2.1、加载本地网页2.2、加载在线网页2.3、网页缩放2.4、文本缩放2.5、web组件事件以及状态说明2.6、处理页面导航 1、通过HTTP请求网络 官方API文档地址&#xff1a;HTTP数据请求-Network Kit数据传输能力-Network Kit&#xff08;网络…

中秋节程序员一般在干啥?

中秋节作为一个传统的中国节日&#xff0c;主要庆祝活动围绕着家庭团聚、赏月、吃月饼等文化习俗展开。然而&#xff0c;对于程序员这个职业群体来说&#xff0c;他们的中秋节活动可能因工作性质和个人安排而有所不同。但大致上&#xff0c;程序员在中秋节期间可能会有以下几种…

嵌入式软件工程师:科技浪潮中的关键角色

嵌入式软件工程师&#xff1a;科技浪潮中的关键角色 一、嵌入式软件工程师的职业魅力 &#xff08;一&#xff09;市场需求旺盛 嵌入式软件工程师在当今科技领域中扮演着至关重要的角色。随着智能化时代的到来&#xff0c;嵌入式系统在各个行业的应用越来越广泛&#xff0c;市…

kaggle竞赛(Deepfake检测)的核心流程【notebook 运行演示】

关注B站可以观看更多实战教学视频&#xff1a;hallo128的个人空间 notebook 链接 从kaggle竞赛零基础上手CV实战 kaggle竞赛&#xff08;Deepfake检测&#xff09;的核心流程 赛题介绍环境配置&#xff08;准备工作&#xff09;数据集神经网络/深度学习的组成元素训练策略/训练…

Linux第五章 文本编辑器vim

Linux第五章 文本编辑器vim 文章目录 Linux第五章 文本编辑器vim常用操作使用技巧 常用操作 vim简介 vi/vim是一个功能强大的全屏幕文本编辑器, 作用是创建, 编辑, 显示文本文件. 它没有菜单, 只有命令. vim工作模式 编辑 进入编辑模式 命令作用i在光标所在字符前插入a在光…

电脑安装OpenWRT系统

通过网盘分享的文件&#xff1a;OpenWRT 链接: https://pan.baidu.com/s/1nrRBeKgGviD31Omji480qA?pwd9900 提取码: 9900 下面开始教程&#xff1a; 1.先把普通U盘制作成一个PE启动盘&#xff0c;我用的是微PE工具箱&#xff0c;直接安装PE到U盘。 2.把写盘工具和openWRT系统…