常见动态内存分配malloc()/free()、new/delete使用方法及常见错误

1.动态内存分配的几种方式
①从静态存储区分配内存,内存在编译时已经分配好了,这块内存在整个程序运行期间都存在,比如全局变量
②从栈上分配内存,函数体结束时,栈内存自动销毁,比如局部变量
③从堆上开辟内存,比如malloc()/new
2.malloc()和free()的使用方法
malloc()/free()用来动态分配内存,使用方法如下:

void *malloc(size_t  size);//动态一块开辟size字节大小的内存
void free(void* ptr);               //释放ptr指向的一块内存空间

举例说明malloc()/free()的使用方法

int *p=(int*) malloc(100);    //指针p指向一个内存空间为100个字节的地址
int *p=(int*) malloc(25*sizeof(int));    //指针p指向25个整型的空间

由于malloc()的返回值类型为void*,所以在函数前面要进行相应的强制类型转换
另外还有两个内存分配的函数calloc()和realloc(),它们的函数原型如下:

void* calloc(size_t num,size_t size);//在内存的动态存储区分配N块长度为size字节的内存,并初始化为0
void* realloc (void* ptr, size_t size);     //将ptr的内存大小增大到size,增加的内存没有进行初始化

calloc()和realloc()的使用举例如下:

int  *p = (int*) calloc (i,sizeof(int));
int *p = (int*) realloc (numbers, count * sizeof(int));

malloc()和calloc()的主要区别主要有:calloc在返回指向内存的指针之前会首先将内存初始化为0;calloc()的参数包含所需元素的数量和每 个元素所包含的字节数
realloc()用于修改原先已经分配内存块的大小,可以扩大和缩小事先分配好的内存块大小。如果要扩大内存,原来的内存大小保持不变,直接在原来的内存块尾部增加新的内存块,且不进行初始化;如果原先的内存块无法扩充,则新开辟一块内存,并复制原内存块中的内容,原先内存块失效再无法进行访问;如果要缩小内存,则直接在原来内存块的尾部直接删减即可。
3.new和delete的使用方法
new/delete 动态管理对象
new[]/delete[] 动态管理对象数组
下面举例说明new/delete的使用方法:

int *p1=new int;   //动态分配4个字(一个整型)节的空间单个数据
int *p2=new int(3); //动态分配4个字(一个整型)节的空间并初始化为3
int  *p3=new  int[3];    //调用operator new动态分配12个字节(3个int)的空间,调用了3次构造函数,operator new相当                                         于malloc

delete p1;
delete p2;
delete[] p2;                //调用3次析构函数

malloc()/free(),new/delete,new[]/delete[]一定要记得匹配使用哦!否则会内存泄漏甚至崩溃
new/delete,new[]/delete[]的底层调用
new/delete:
这里写图片描述
new[]/delete[]
这里写图片描述
4.malloc()/free()和new/delete的区别
有了malloc()/free(),为什么还要用new/delete,二者有何区别?
malloc()/free()和new/delete都可以用于动态内存的申请和释放。但对于非静态内部数据类型的对象而言,对象在消亡之前要自动的执行析构函数,由于malloc/free是库函数,而不是运算符,不在编译器控制范围之内不能把执行构造函数和析构函数的任务强加给malloc()/free(),所以只能用new/delete运算符。
区别:①new是构造一个对象,并调用构造函数来初始化对象,其实在new的所有操作过程中总共分为两步: 申请内 存;调用构造函数。在调用delete时,先调用析构函数,再销毁堆内存
②malloc()/free() C/C++标准库函数,new/delete是C++的操作符
③new/delete支持重载,重载之后就成了函数。
④new/delete内部实现实质上也调用了malloc()/free()
⑤malloc()/free()需要手动计算类型大小,返回void*指针,new/delete可以自己计算类型大小,返回对应类型的指针
⑥malloc()申请内存失败会返回一个空指针,new申请内存失败会抛bad_alloc异常或者返回空指针
5.什么情况下会malloc()和new失败?
①内存不足时,会出现内存失败
②前面的程序出现了一些内存的越界访问,导致malloc()分配函数所涉及的一些信息被破坏,下次使用malloc()申请内存时就会malloc() 失败,返回NULL
6.动态内存传递问题
在函数体内定义的临时变量函数结束时,栈上的内存就会自动销毁,如果想返回变量,可以在堆上开辟一段新的内存

void GetMemory(char *p,int mum)
{
   p=(char*)malloc(sizeof(char)*num);
}
int main()
{
   char *str=NULL;
   GetMemory(str,10);
   strcpy(str,"hello");
}

这段程序存在两个严重的问题:
①p实质上只是str的一份临时备份,虽然p申请了堆内存,但返回main()函数时,str还是NULL,执行strcpy()函数时,会导致程序崩溃
②从Memory()函数返回时不能获得堆中的地址,那块内存就不能被继续使用,也得不到释放,因此调用一次Memory()函数就会产生mun个字节的内存泄漏
解决以上的内存泄漏问题有如下三种方法:
①C语言中,采用指向指针的指针解决这个问题,把str的地址传递给函数GetMemory()
②在C++中,传递str指针的引用
③使用返回值来传递内存

void GetMemary1(char **p,int num)
{
  *p=(char*)malloc(sizeof(char)*num);
}
void GetMemary2(char * &p,int num)
{
  p=(char*)malloc(sizeof(char)*num);
}
void *GetMemary3(int num)
{
  char *p=(char*)malloc(sizeof(char)*num);
return p;
}

猜你喜欢

转载自blog.csdn.net/wyn126/article/details/79621529