malloc与new相关

  malloc函数:malloc的全称是memory allocation,中文叫动态内存分配。作用是向系统申请分配指定size个字节的内存空间,函数原型为:

extern void *malloc(unsigned int num_bytes);

  void*表示未确定类型的指针,C,C++规定,void* 类型可以通过类型转换强制转换为任何其它类型的指针。

  free函数:void free(void *FirstByte): 该函数是将之前用malloc分配的空间还给程序或者是操作系统,也就是释放了这块内存,让它重新得到自由。

  其功能为在堆中申请一块连续的可用的内存;使用中有如下需要关注的点:

  1.malloc分配的内存大小至少为size参数所指定的字节数.

  2.malloc的返回值是一个指针,指向一段可用内存的起始地址.

  3.多次调用malloc所分配的地址不能有重叠部分,除非某次malloc所分配的地址被释放掉.

  4.malloc应该尽快完成内存分配并返回.

  5.实现malloc时应同时实现内存大小调整和内存释放函数(即realloc和free).

用法示例:

#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
int main() {
    char *ptr;
    ptr = (char*)malloc(8);   //返回类型为void*,强制转换
    if (NULL == ptr)          //申请后务必检查是否成功,因为对内存不足等原因有可能申请失败
    {
          exit (1);
    } 

    if(ptr)
        printf("Memory Allocated at: %x/n",ptr);
    free(ptr);                //申请同时释放
    ptr = NULL;               //free释放的只是内存,ptr指针还在,所以记得将ptr指向NULL
    return 0;
}

malloc函数使用时需要注意的要点:

  1、如果有足够空间用于扩大mem_address指向的内存块,则分配额外内存,并返回mem_address.  这里说的是“扩大”,我们知道,realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平。也就是说,如果原先的内存大小后面还有足够的空闲空间用来分配,加上原来的空间大小= newsize,得到的是一块连续的内存。

  2、如果原先的内存大小后面没有足够的空闲空间用来分配,那么从堆中另外找一块newsize大小的内存。  并把原来大小内存空间中的内容复制到newsize中。返回新的mem_address指针。

  3、malloc函数返回值情况

  返回的是一个void类型的指针,调用成功。(这就再你需要的时候进行强制类型转换)

  返回NULL,当需要扩展的大小(第二个参数)为0并且第一个参数不为NULL,此时原内存变成了“freed(游离)”的了。

  返回NULL,当没有足够的空间可供扩展的时候,此时,原内存空间的大小维持不变。

  4、malloc函数的特殊情况

  如果mem_address为null,则realloc()和malloc()类似。分配一个newsize的内存块,返回一个指向该内存块的指针。

  如果newsize大小为0,那么释放mem_address指向的内存,并返回null。

  如果没有足够可用的内存用来完成重新分配(扩大原来的内存块或者分配新的内存块),则返回null而原来的内存块保持不变。

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

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

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

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

malloc()函数和free()函数的机制说明

malloc函数原理

  malloc()到底从哪里分配到内存空间?答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。关于堆的知识呢可以查询数据结构方面的知识。在使用malloc()分配内存空间后,一定要记得释放内存空间,否则就会出现内存泄漏。

free函数原理

  free()到底释放了什么?free()释放的是指针指向的内存!注意!释放的是内存,不是指针!指针并没有被释放,指针仍然指向原来的存储空间。指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。因此,释放内存后把指针指向NULL,防止指针在后面不小心又被解引用了。free()的函数原型非常简单,只有一个参数,只要把指向申请空间的指针传递给free()中的参数就可以完成释放工作!这里要追踪到malloc()的申请问题了。申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等。这就意味着如果写过一个已分配区的尾端,则会改写后一块的管理信息。这种类型的错误是灾难性的,但是因为这种错误不会很快就暴露出来,所以也就很难发现。将指向分配块的指针向后移动也可能会改写本块的管理信息。

 new运算符:

  动态创建对象时,只需指定其数据类型,而不必为该对象命名,new表达式返回指向该新创建对象的指针,我们可以通过指针来访问此对象。

int *pi=new int;

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

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

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

  如果不提供显示初始化,对于类类型,用该类的默认构造函数初始化;而内置类型的对象则无初始化。

也可以对动态创建的对象做值初始化:

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

delete运算符

  释放指针指向的地址空间。

  delete p; //执行完该语句后,p变成了不确定的指针,在很多机器上,尽管p值没有明确定义,但仍然存放了它之前所指对象的地址,然后p所指向的内存已经被释放了,所以p不再有效。此时,该指针变成了悬垂指针(悬垂指针指向曾经存放对象的内存,但该对象已经不存在了)。悬垂指针往往导致程序错误,而且很难检测出来。

  一旦删除了指针所指的对象,立即将指针置为0,这样就非常清楚的指明指针不再指向任何对象。(零值指针:int *ip=0;)

区分零值指针和NULL指针

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

new分配失败时,返回什么?

  1993年前,c++一直要求在内存分配失败时operator new要返回0,现在则是要求operator new抛出std::bad_alloc异常。很多c++程序是在编译器开始支持新规范前写的。c++标准委员会不想放弃那些已有的遵循返回0规范的代码,所以他们提供了另外形式的operator new(以及operator new[])以继续提供返回0功能。这些形式被称为“无抛出”,因为他们没用过一个throw,而是在使用new的入口点采用了nothrow对象:

malloc与new的区别:

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

int* ptr 1= new int [100];  //返回类型为int*,分配大小为sizeof(int)*100字节;

int* ptr2 = (int *)malloc(100); //返回类型为void*,需要强制转换为int*,分配大小为100字节;

  2、malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的。除了分配及最后释放的方法不一样以外,通过malloc或new得到指针,在其它操作上保持一致。

有malloc/free为什么还需要new/delete?

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

  2) 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。

  因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。

  我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。

  3) 既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。

  如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存”,结果也会导致程序出错,但是该程序的可读性很差。所以  new/delete必须配对使用,malloc/free也一样。

时间: 2024-11-03 21:24:25

malloc与new相关的相关文章

malloc和free的内存到底有多大?——GNU glib库

大家应该都比较熟悉这一点:malloc分配的内存一定大于用户指定的大小!而且很多人也问过这样的问题:到底大多少?以及实际上malloc到底分配了多少? 我们知道这个大小一定在某个"神奇"地方记录着,但是就像自己的"思维"一样,你确无法感知!不过,这是错觉,只是我们习惯了只使用,而没有深入剖析源码,在这里我将揭开这个面纱,去掉其透明化! 声明:源码基于GNU glib库的2.7版本的malloc目录下相关文件 再声明:不同的C库实现方式不一定一样,这里是glib库,如

C++—new/delete/malloc/free详解

主要内容: 1.  C语言中的函数malloc和free 2.  C++中的运算符new和delete 3.  new/delete与malloc/free之间的联系和区别 4.  C/C++程序的内存分配介绍 详细介绍: C语言的函数malloc和free (1) 函数malloc和free在头文件<stdlib.h>中的原型及参数 void * malloc(size_t size) 动态配置内存,大小有size决定,返回值成功时为任意类型指针,失败时为NULL. void free(vo

关于c语言内存分配,malloc,free,和段错误,内存泄露

1.   C语言的函数malloc和free (1) 函数malloc和free在头文件<stdlib.h>中的原型及参数        void * malloc(size_t size) 动态配置内存,大小有size决定,返回值成功时为任意类型指针,失败时为NULL. void  free(void *ptr) 释放动态申请的内存空间,调用free()后ptr所指向的内存空间被收回,如果ptr指向未知地方或者指向的空间已被收回,则会发生不可预知的错误,如果ptr为NULL,free不会有任

const对象,NULL和nullptr,C++中创建对象数组

 1.定义成了const之后的类 #include <iostream> class area { public: int x; int y; mutable int z; //不受const约束的类成员 area() :x(10), y(10), z(2) { } void printxy()const //不可以访问类中局部变量 { z = z + 1; std::cout << x << " " << y << &q

C语言--存储类、链接和内存管理

注:此文为<C Primer Plus>一书中的部分总结,写下来方便以后参考. 用于存储程序数据的内存可用存储时期.作用域和链接来表征. 存储时期可以使静态的.自动的或者分配的.①如果是静态的,内存在程序开始执行时被分配,并行程序运行时一直存在.②如果是自动的,变量所用内存在程序执行到该变量定义所在代码块时开始分配,在退出代码块时释放.③如果是分配的内存,内存通过调用malloc()(或其他相关函数)分配,通过调用函数free()释放. 作用域决定哪一部分程序可以访问某个数据.在所有函数之外定

Linux内存模型

了解linux的内存模型,或许不能让你大幅度提高编程能力,但是作为一个基本知识点应该熟悉.坐火车外出旅行时,即时你对沿途的地方一无所知,仍然可以到达目标地.但是你对整个路途都很比较清楚的话,每到一个站都知道自己在哪里,知道当地的风土人情,对比一下所见所想,旅程可能更有趣一些. 类似的,了解linux的内存模型,你知道每块内存,每个变量,在系统中处于什么样的位置.这同样会让你心情愉快,知道这些,有时还会让你的生活轻更松些.看看变量的地址,你可以大致断定这是否是一个有效的地址.一个变量被破坏了,你可

nginx源码解析之内存池

nginx自身实现了内存池,所有内存分配都是基于内存池来操作.基本思想是预申请一段内存空间,低于指定大小的内存(小段内存)直接从内存池中申请,超过指定大小的内存(大段内存)直接调用malloc申请.相关代码在os/unix/ngx_alloc.{c,h}和core/ngx_palloc.{c,h}. os/unix/ngx_alloc.{c,h}文件封装了内存分配的系统调用,其中: ngx_alloc调用malloc申请一段内存空间 ngx_calloc调用malloc申请一段内存空间,再调用m

Linux-(C/C++)动态内存分配malloc以及相关学习

1.C/C++内存分类(引用C++ Primer )(对象在C语言中可以理解为变量) 1.1.静态内存:静态内存用来保存局部static对象.类static数据成员.以及定义在任何函数之外的变量 1.2.栈内存:栈内存用来保存定义在函数内非static对象.(当然包含函数参数开辟的内存) 1.3.动态内存:每个程序还有一个内存池,这部分内存被称作自由空间(free store)或者堆(heap).程序用堆来存储动态分配的内存(dynamically allocate)的对象,也就是,那些在程序运

二叉树的相关操作

#include<stdio.h> #include<malloc.h> #define MAXSIZE 20 typedef char TEelemtype; typedef struct BiTNode{ TEelemtype data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; //队列的方式 typedef struct queueelem { BiTNode* b[MAXSIZE]; int front,rear;