new malloc

https://blog.csdn.net/happyxieqiang/article/details/50775847

 

0.       属性

new/delete是C++关键字,需要编译器支持。malloc/free是库函数,需要头文件支持。

1.       参数

使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。

2.       返回类型

new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。

3.       分配失败

new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。

4.      自定义类型

         new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。

         malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。

5.      重载

C++允许重载new/delete操作符,特别的,布局new的就不需要为对象分配内存,而是指定了一个地址作为内存起始区域,new在这段内存上为对象调用构造函数完成初始化工作,并返回此地址。而malloc不允许重载。

6.       内存区域

new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆,如上所述,布局new就可以不位于堆中。

 

 

今天偶然看到一个面试经验中提到malloc和new的区别,突然发现自己虽然两个都用过,但是至于区别,真的不是很明白 ,所以就仔细查了一些资料,算是对这个点彻底地了解一下,现在把我所学到的记录下来。

malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。

1.malloc函数初探

首先我们要知道malloc是一个函数,malloc的全称是memory allocation,中文叫动态内存分配。它的原型是:

void *malloc(int size);
  • 1

说明:malloc 向系统申请分配指定size个字节的内存空间,返回类型是 void* 类型。void* 表示未确定类型的指针。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。    
在这里注意: 
(1) void* 表示未确定类型的指针,更明确的说是指申请内存空间时还不知道用户是用这段空间来存储什么类型的数据(比如是char还是int或者…) 
(2) 使用malloc向系统申请内存时可能分配失败。如果分配失败,则返回一个空指针(NULL)。关于分配失败的原因,有很多种,比如说空间不足就是一种。 
一个对应的释放内存的函数:

void free(void *FirstByte);
  • 1

该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。 
至于用法,其实这两个函数用起来倒不是很难,也就是malloc()之后觉得不用了需要释放把它给free()了,举个简单例子:

char *Ptr = NULL; 
Ptr = (char *)malloc(100 * sizeof(char)); if (NULL == Ptr){ exit (1); } gets(Ptr); free(Ptr); Ptr = NULL; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

当然,具体情况要具体分析以及具体解决。比如说,你定义了一个指针,在一个函数里申请了一块内存然后通过函数返回传递给这个指针,那么也许释放这块内存这项工作就应该留给其他函数了。只要保证每个malloc()之后必须有一个free()与之对应。

关于这个函数的用法需要注意的一些地方:

1.申请了内存空间后,必须检查是否分配成功。

2.当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。

3.这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。

4.虽然malloc()函数的类型是void*,任何类型的指针都可以转换成void*,但是最好还是在前面进行强制类型转换,因为这样可以躲过一些编译器的检查。

2.malloc函数深入

看了以上的内容我们大致知道malloc函数的初步内容以及它的用法,但是我们不知道malloc函数是怎么实现动态分配内存的。那它是怎么动态分配内存的呢?

答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。

说到这里就不得不提堆,什么是堆呢?堆是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。堆在操作系统对进程 初始化的时候分配,运行过程中也可以向系统要额外的堆,记住一点:从堆申请的内存用完了要还给操作系统,也就是释放,如果不还的话会发生内存泄露。

而所谓内存泄露就好比你去食堂吃饭,你吃完了之后没把盘子拿走,这在别人看来是这个座有人占了,可怕的是你回头吃饭又占了一个新座,你吃完之后还是没把盘子拿走……终于,整个食堂的座位都被占满了,食堂也乱套了。(比喻不太恰当,但大致是这个意思)

平常我们老说堆栈、堆栈,那栈又是什么呢?栈是线程独有的,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈互相独立。每个函数都有自己的栈,栈被用来在函数之间传递参数。操作系统在切换线程的时候会自动的切换栈,就是切换SS/ESP寄存器。栈空间不需要在高级语言里面显式的分配和释放。

通过上面对概念的描述,可以知道:

栈是由编译器自动分配释放,存放函数的参数值、局部变量的值等。操作方式类似于数据结构中的栈。

堆一般由程序员分配释放,若不释放,程序结束时可能由操作系统回收。注意这里说是可能,并非一定。所以堆一定要释放!

3.new运算符

3.1 C++中,用new和delete动态创建和释放数组或单个对象。 
动态创建对象时,只需指定其数据类型,而不必为该对象命名,new表达式返回指向该新创建对象的指针,我们可以通过指针来访问此对象。

int *pi=new int;
  • 1

这个new表达式在堆区中分配创建了一个整型对象,并返回此对象的地址,并用该地址初始化指针pi 。

3.2 动态创建对象的初始化

动态创建的对象可以用初始化变量的方式初始化。

int *pi=new int(100); //指针pi所指向的对象初始化为100 string *ps=new string(10,'9');//*ps 为“9999999999”
  • 1
  • 2

如果不提供显示初始化,对于类类型,用该类的默认构造函数初始化;而内置类型的对象则无初始化。 
也可以对动态创建的对象做值初始化:

int *pi=new int( );//初始化为0
int *pi=new int;//pi 指向一个没有初始化的int string *ps=new string( );//初始化为空字符串 (对于提供了默认构造函数的类类型,没有必要对其对象进行值初始化)
  • 1
  • 2
  • 3

3.3 撤销动态创建的对象 
delete表达式释放指针指向的地址空间。

delete pi ;// 释放单个对象
delete [ ]pi;//释放数组
  • 1
  • 2

如果指针指向的不是new分配的内存地址,则使用delete是不合法的。

3.4 在delete之后,重设指针的值

delete p; 
  • 1

执行完该语句后,p变成了不确定的指针,在很多机器上,尽管p值没有明确定义,但仍然存放了它之前所指对象的地址,然后p所指向的内存已经被释放了,所以p不再有效。此时,该指针变成了悬垂指针(悬垂指针指向曾经存放对象的内存,但该对象已经不存在了)。悬垂指针往往导致程序错误,而且很难检测出来。 
一旦删除了指针所指的对象,立即将指针置为0,这样就非常清楚的指明指针不再指向任何对象。(零值指针:int *ip=0;

3.5 区分零值指针和NULL指针

零值指针,是值是0的指针,可以是任何一种指针类型,可以是通用变体类型void*也可以是char*,int*等等。 
空指针,其实空指针只是一种编程概念,就如一个容器可能有空和非空两种基本状态,而在非空时可能里面存储了一个数值是0,因此空指针是人为认为的指针不提供任何地址讯息。

4.malloc和new的区别

(1) new 返回指定类型的指针,并且可以自动计算所需要大小。而 malloc 则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。 
例:

//new
int *p;   
p = new int; //返回类型为int* 类型(整数型指针),分配大小为 sizeof(int); int* parr;    parr = new int [100]; //返回类型为 int* 类型(整数型指针),分配大小为sizeof(int) * 100; //malloc int* p;    p = (int *) malloc (sizeof(int)*128);//分配128个(可根据实际需要替换该数值)整型存储单元,并将这128个连续的整型存储单元的首地址存储到指针变量p中 double *pd=(double *) malloc (sizeof(double)*12);//分配12个double型存储单元,并将首地址存储到指针变量pd中
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

(2) malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的。new创建的对象可以用初始化变量的方式初始化。

除了分配及最后释放的方法不一样以外,通过malloc或new得到指针,在其它操作上保持一致。

转载于:https://www.cnblogs.com/diegodu/p/9190717.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/570723.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pip install scrpy 报错: command 'gcc' failed with exit status 1

报错如下: copying src/twisted/words/xish/xpathparser.g -> build/lib.linux-x86_64-2.7/twisted/words/xish running build_ext building twisted.test.raiser extension creating build/temp.linux-x86_64-2.7 creating build/temp.linux-x86_64-2.7/src cr…

Codeforces 990E Post Lamps 【暴力】【贪心】

虽然只是10^6的数据量,但用cin会tle。一直知道cin常数大,但没想到会是10^2这个级别。 我们枚举每个power的lamp,然后对每个power用平均logn的代价去求它的cost,最后取最小值 对于每个power,我们从左往右地去照亮整个区…

[Luogu 2486] SDOI2011 染色

[Luogu 2486] SDOI2011 染色 树剖水题&#xff0c;线段树维护。 详细题解不写了。 我只想说我写的线段树又变漂亮了qwq #include <algorithm> #include <cstdio> #include <cstring> const int MAXN100010; int n,m; class HLD {private:bool vis[MAXN];int …

完全卸载HDP和Ambari

文章转载自&#xff1a;https://imaidata.github.io/blog/uninstall_hdp_ambari/ 用于个人学习、备查&#xff0c;转载请注明原作者。 简介&#xff1a; 在不需要重装操作系统的情况下完全卸载HDP&#xff0c;并准备好自动安装HDP2.6的环境。 文章&#xff1a; 升级HDP失败…

HBase 配置详解

文章转载自&#xff1a;http://blog.csdn.net/ningxuezhu/article/details/50547970 仅用于个人学习&#xff0c;收藏&#xff0c;作为资料备查&#xff0c;如需转载请注明原作者。 该文档是用hbase默认配置文件生成的&#xff0c;文件源是hbase-default.xml hbase.rootdir …

文件拷贝(字符、字节)

1.字节流byte&#xff1a;读入到字节数组后&#xff0c;返回一个长度len&#xff0c;如果没有读到数据&#xff0c;len-1 2.字符流char&#xff1a;同样是-1 3.代码生成器&#xff1a;null 一行一行地读 4.键盘录入&#xff0c;写入文件 5.构造器&#xff0c;追加用true 6.类…

HBae找不到协处理器导致RegionServer全部挂掉

一、问题背景&#xff1a; 跟兄弟单位公用一个大数据集群&#xff0c;通过Dataspace结合Kerberos控制数据的访问&#xff0c;我们生产环境中用到的OLAP工具Kylin&#xff0c;在升级Kylin的过程中&#xff0c;由于删除了旧的协处理器&#xff0c;导致原来数据继续去寻找目标协处…

Spark SQL的整体实现逻辑

1、sql语句的模块解析 当我们写一个查询语句时&#xff0c;一般包含三个部分&#xff0c;select部分&#xff0c;from数据源部分&#xff0c;where限制条件部分&#xff0c;这三部分的内容在sql中有专门的名称&#xff1a; 当我们写sql时&#xff0c;如上图所示&#xff0c;在进…

Mysql的高可用方案及主从详细配置

1、常用的高可用MySQL解决方案&#xff1a; 数据库作为最基础的数据存储服务之一&#xff0c;在存储系统中有着非常重要的地位&#xff0c;因此要求其具备高可用性无可厚非。能实现不同SLA(服务水平协定)的解决方案有很多种&#xff0c;这些方案可以保证数据 库服务器在硬件或…

vue3+element plus组件库中el-carousel组件走马灯特效,当图片变动时下面数字也随着图片动态变化

1.效果图 2.html <section style"height:30%"><div class"left-img1-title"><img src"../assets/img/title.png"alt""srcset""><div class"text">回收垃圾数量</div></div>…

数据库MySQL/mariadb知识点——数据类型

数据类型 所谓的列类型&#xff0c;其实就是指数据类型&#xff0c;即对数据进行统一的分类&#xff0c;从系统的角度出发是为了能够使用统一的方式进行管理&#xff0c;更好的利用有限的空间。 在 SQL 中&#xff0c;将数据类型分成了三大类&#xff0c;分别为&#xff1a;数值…

HDFS查看文件的前几行-后几行-行数

随机返回指定行数的样本数据 hadoop fs -cat /test/gonganbu/scene_analysis_suggestion/* | shuf -n 5 返回前几行的样本数据 hadoop fs -cat /test/gonganbu/scene_analysis_suggestion/* | head -100 返回最后几行的样本数据 hadoop fs -cat /test/gonganbu/scene_anal…

psql: FATAL the database system is in recovery解决

报错&#xff1a; FATAL: the database system is in recovery mode 解决思路&#xff1a; 在hawq master节点 1、执行hawq state &#xff0c;提示 database is down 2、查看hawq master进程&#xff1a; ps aux | grep postgresql &#xff0c;发现master进程不在 3、查…

软件工具组功能逆向工程设想

背景&#xff1a;昨天小智公布了软件工具组现在的几个项目组&#xff0c;大概罗列了现阶段软件工具组的主要职能&#xff0c;总结起来说就是将现有设计方案生成渲染图、全景图、视频、CAD等&#xff0c;看完所有这些功能我不禁设想了一下&#xff0c;如果软件工具组的功能逆向工…

FAIL : SSHException: Incompatible ssh peer (no acceptable kex algorithm)

问题描述&#xff1a; 在安装greenplum&#xff0c;执行gpssh-exkeys过程中抛出异常 Incompatible ssh peer (no acceptable kex algorithm) 原因&#xff1a; 由于ssh 6.7以上屏蔽不安全算法 解决&#xff1a; 在/etc/ssh/sshd_config最后加上 KexAlgorithms curve25519…

集群监控之Ganglia的部署

转载地址&#xff1a;https://www.slothparadise.com/how-to-install-ganglia-on-centos-7/ 找了一堆文章&#xff0c;全都误导了&#xff0c;这篇正解。 总结步骤如下&#xff1a; 1、server端 &#xff1a; yum install -y ganglia-gmetad ganglia-web ganglia-gmond rrd…

期货大赛项目|九,fileinput插件的应用

引入JS和CSS bundles.Add(new ScriptBundle("~/bundles/fileinputJs").Include( "~/Content/vendors/bootstrap-fileinput-master/js/fileinput.min.js", "~/Content/vendors/bootstrap-fileinput-master/js/locales/zh.js", "~/Scripts/fi…

redis见解

http://blog.csdn.net/zhiguozhu/article/details/50517527Redis原生session与redis中的session区别原生session在服务器上是以文件的形式存储的&#xff0c;所以其有一些磁盘io上的缺点 1&#xff09; 有哪几种类型的数据结构String——字符串  value 不仅可以是 String&…

快速解读GC日志

文章转载自&#xff1a;http://blog.csdn.net/renfufei/article/details/49230943 本文是 Plumbr 发行的 Java垃圾收集指南 的部分内容。文中将介绍GC日志的输出格式, 以及如何解读GC日志, 从中提取有用的信息。我们通过 -XX:UseSerialGC 选项,指定JVM使用串行垃圾收集器, 并使…

HBase meta元数据损坏导致hbase master初始化失败

故障起因&#xff1a; 跑kylin任务&#xff0c;过程出错&#xff0c;异常信息&#xff1a;Direct buffer memory&#xff0c; java.io.IOException: java.lang.OutOfMemoryError: Direct buffer memoryat org.apache.hadoop.hbase.regionserver.HRegion$RegionScannerImpl.ha…