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得到指针,在其它操作上保持一致。

new malloc的更多相关文章

  1. malloc 与 free函数详解<转载>

    malloc和free函数详解   本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...

  2. C 语言中 malloc、calloc、realloc 和free 函数的使用方法

    C标准函数库中,常见的堆上内存管理函数有malloc(), calloc(), recalloc(), free(). 之所以使用堆,是因为栈只能用来保存临时变量.局部变量和函数参数.在函数返回时,自 ...

  3. 以冒泡排序为例--malloc/free 重定向stdin stdout

    esort.c 代码如下,可关注下mallloc/free,freopen重定向的用法,排序为每轮将最小的数放在最前面: #include<stdio.h> #include<mal ...

  4. 内存动态分配之realloc(),malloc(),calloc()与new运算符

    1,malloc与free是C/C++的标准库函数,new/delete是C++的运算符,是C++面向对象的特征,它们都可用于申请动态内存和释放内存.2,对于非内部数据类型的对象而言,光用maloc/ ...

  5. 在dll里malloc/new/cvCreate分配内存,在exe里free/Releases释放内存时会出错。

    写了个程序,在DLL中用malloc分配了一块内存,但是在exe程序中释放,结果程序crash,原因就是:其原因可能是堆被损坏,这也说明 TestMySticker.exe 中或它所加载的任何 DLL ...

  6. Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解

    C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般 ...

  7. malloc与new的区别

    1.new是运算符,而malloc是库函数 2.new可以重载,可以自定义内存分配策略,甚至不做内存分配,甚至分配到非内存设备上.而malloc不能. 3.new在用于定义一个新的非内部对象的时候,默 ...

  8. new 等于 malloc加构造函数

    1.new 是c++中的操作符,malloc是c 中的一个函数 2.new 不止是分配内存,而且会调用类的构造函数,同理delete会调用类的析构函数,而malloc则只分配内存,不会进行初始化类成员 ...

  9. 关于malloc函数的动态分配问题

    malloc函数动态分配了一个整型的内存空间,让abc都指向刚申请的空间,所以只有最后一个赋值语句的值保留在了空间里 #include<stdio.h> main() { int *a,* ...

  10. 转:如何实现一个malloc

    如何实现一个malloc 转载后排版效果很差,看原文!   任何一个用过或学过C的人对malloc都不会陌生.大家都知道malloc可以分配一段连续的内存空间,并且在不再使用时可以通过free释放掉. ...

随机推荐

  1. HTML5实现简单圆周运动示例

    一.使用JS实现圆周运动 根据指定圆心.半径,在定时器中移动固定的弧度,重绘圆圈的位置 源代码: <!DOCTYPE html> <html lang="en"& ...

  2. C++对带有分隔符的字符串 分割为数字的通用解决方案

    需求: 数据库取出的字段类似于 "1,3,4" 然后用数字处理后,,比如 "1,2,3" 再存回去 #include<stdio.h> #inclu ...

  3. 第十三章 redis-cluster原理

    一.基本定义 虚拟槽slot分区算法,优点是扩容缩容简单:直接把slot及每个slot上的数据进行缩放即可 redis定义了0-16383(总共为16384个slot,即214个slot) slot会 ...

  4. iOS开发-音乐播放(AVAudioPlayer)

    现在的手机的基本上没有人不停音乐的,我们无法想象在一个没有声音的世界里我们会过的怎么样,国内现在的主流的主流网易云音乐,QQ音乐,酷狗,虾米,天天基本上霸占了所有的用户群体,不过并没有妨碍大家对音乐的 ...

  5. OJ模板库

    近期刷了好几次的oj,好受伤好多都是相似的题目. 最长回文子串 string preprocess(string &str) { string afterProcessStr="#& ...

  6. HDU 1234 (浙大计算机研究生复试上机考试-2005年) 开门人和关门人 (水)

    开门人和关门人 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su ...

  7. Android -- isInEditMode

    解释 Indicates whether this View is currently in edit mode. A View is usually in edit mode when displa ...

  8. Is there anyway to discover which ip addresses are connected to the db?

    From mongo shell run db.currentOp() to show all active connections or db.currentOp(true) to show all ...

  9. Java集合遍历时删除

    public static void main(String[] args){ List<Integer> list = new ArrayList<Integer>(); l ...

  10. [Angular CLI] Build application without remove dist folder for Docker Volume

    When we develop the Angular app inside Docker container, we can simulate Production envioment by bui ...