目录
- 为什么要有动态内存管理
- malloc
- calloc
- realloc
- 柔性数组
- 柔性数组的特点
- 柔性数组的使用
- 柔性数组的好处
动态内存管理
为什么要有动态内存管理
我们目前已知道的开辟内存空间的方式如下
inta=4;//向栈区申请四个字节的空间chari[10]={0};//向栈区申请连续的10个字节空间上述申请空间的方式有如下特点
- 申请后,空间的大小是固定的
- 数组在声明空间大小后,空间的大小就不能更改了
可是在我们运行程序时,很多时候内存的大小是要在运行程序的过程中才知道的,这就意味着对提前申请的静态空间,可能造成空间的浪费或者溢出。
于是c语言就引用了动态内存管理,允许程序员实时申请或者释放内存,以达到高效利用。
malloc
void*malloc(size_tsize)功能:向堆区申请一块连续的空间,并返回这块空间的起始地址。
参数:size:表示要申请空间的字节数大小
- 若申请成功,则返回这块空间的起始地址。
- 若申请失败(比如内存不足),则返回一个空指针NULL,因此在使用时,要注意检查返回值是否为NULL
- 由于返回值的类型是void*,因此接受指针还要根据数据类型来定义
注意事项:
- 若参数size为0,则是标准的未定义行为,可能会导致错误。
- 要包含头文件<stdlib.h>
功能:用来释放之前动态内存函数(realloc,calloc,malloc)申请的动态空间使用前要包含头文件<stdlib.h>
参数:ptr指向要释放空间的起始地址
注意事项
- 若ptr指向的内存空间是静态的,则该行为未定义
- 若ptr是空指针NULL,那么free函数什么也不会做
- 在释放完ptr指向的动态空间后,一般把该指针置为NULL
calloc
void*calloc(size_tnum,size_tsize);功能:在堆区上申请num个大小为size个字节的空间,并把每个空间的每个字节初始化为0
其他与malloc类似,唯一的区别是calloc会把申请空间的每一个字节初始化为0
realloc
- realloc的出现让动态内存分配更灵活
- 当我们发现过去申请的内存过大或者过小,可以通过realloc重新进行动态内存分配
void*realloc(void*ptr,size_tsize);功能:重新分配原有内存块的大小,在不丢失原有内存块中数据的前提下,合理扩大或缩小内存。
参数:
- ptr指向要调整内存块的起始地址,如果ptr是空指针NULL,则realloc的功能类似malloc。
- size表示要分配内存的大小(单位字节)
返回值 - 成功:返回该内存块的起始地址,该指针可能和ptr相同或者不同
- 失败:返回NULL指针,并且保持原来内存块不变。
注意事项
realloc在追加空间时,有以下两种情况 - 当原有空间充足时,会直接在原有空间后面追加空间,数据内存不变,返回传入的地址。
- 当原有空间不够时候,会在堆区中寻找内存足够的空间,并返回新地址,有如下过程
- 开辟空间
- 将原有数据拷贝到新的空间,保证数据不丢失
- 自动释放旧空间
- 返回新空间的起始地址
柔性数组
结构中最后一个元素允许是未知大小的数组,这就叫作柔性数组成员
structst_type{inta;intarr[];//柔性数组成员}柔性数组的特点
- 结构中柔性数组前至少有一个成员
- 使用sizeof计算结构内存大小时,柔性数组不参与内存计算
- 包含柔性数组的结构使用malloc()函数进行内存的动态内存分配,并且分配的大小应该大于结构的大小,以适应柔性数组的预期大小。
柔性数组的使用
#include<stdlib.h>structS{inta;intarr[];};intmain(){structS*p=(structS*)maalloc(sizeof(structS)+5*sizeof(int));for(inti=0;i<5;i++){p->arr[i]=i+1;}structS*ptr=realloc(p,sizeof(structS)+10*sizeof(int));p=ptr;ptr=NULL;for(inti=5;i<10;i++){p->arr[i]=i+1;free(p);p=NULL;}return0;}上述代码也可以通过非柔性数组的方式实现
#include<stdlib.h>structS{inta;int*ps;};intmain(){structS*p=(structS*)malloc(sizeof(structS));p->a=100;int*pp=(int*)malloc(p->a*sizeof(int));p->ps=pp;pp=NULL;for(p->a=0;p->a<100;p->a++){p->ps[p->a]=p->a+1;}free(p->ps);p->ps=NULL;free(p);p=NULL;return0;}柔性数组的好处
从上面的写法对比,可以总从上面的写法对比,可以总结出柔性数组的好处。
第一个好处:方便内存释放
如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这件事。因此,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
第二个好处:有利于访问速度
连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正你跑不了要用做偏移量的加法来寻址)