目录1 动态内存分配常用库函数1.1 free1.2 malloc1.3 calloc1.4 realloc2 常见的动态内存错误2.1 对NULL指针的使用2.2 越界访问2.3 对非动态开辟的空间进行释放2.4 对动态开辟的空间重复释放2.5 释放部分动态开辟的空间2.6 忘记释放动态开辟的内存空间3 柔性数组1 动态内存分配常用库函数1.1 freefree 的函数声明如下voidfree(void*ptr);作用将动态开辟的空间进行回收参数部分指向动态分配内存空间的指针若该指针为空指针则 free 不会做任何事情返回值该函数没有返回值一般来说在使用了 malloc 等函数开辟动态内存空间后若这块空间不需要使用就要用 free 函数来进行回收并将指针置为空防止内存泄露和野指针问题1.2 mallocmalloc 的函数声明如下void*malloc(size_tsize);作用向操作系统申请 size 个字节大小的连续内存空间参数部分要分配的空间大小以字节为单位返回值如果空间开辟成功会返回这块连续内存空间的首地址用户可以根据自己的需要将返回的 void* 类型的指针进行强制类型转换但是如果开辟失败会返回空指针所以用户应该在使用 malloc 后检查指针的值是否为空防止对空指针进行使用举例向操作系统申请 20 个字节大小的空间用于存储 int 类型数据#includestdlib.hintmain(){int*p(int*)malloc(sizeof(int)*5);if(pNULL)//防止对空指针进行使用{perror(malloc);return1;}free(p);//回收开辟的空间pNULL;//防止野指针return0;}int 类型大小 4 个字节乘以 5 就是 20 个字节由于要存放 int 类型数据所以返回的指针强制类型转换为了 int*申请了空间就需要使用那么怎么使用这块空间呢在使用动态开辟的内存空间时可以当成数组来使用通过数组的遍历方式来使用这块空间举例开辟20个字节的空间存放 1 2 3 4 5 并输出#includestdlib.hintmain(){int*p(int*)malloc(sizeof(int)*5);if(pNULL){perror(malloc);return1;}for(inti0;i5;i){*(pi)i1;//*(p i) p[i]}for(inti0;i5;i){printf(%d ,*(pi));}free(p);pNULL;return0;}图解1.3 calloccallo 的函数声明如下void*calloc(size_tnum,size_tsize);作用开辟 num 个大小为 size 的空间并初始化为全 0参数部分num指元素个数size指一个元素的大小返回值开辟成功返回指向动态开辟空间的指针开辟失败则返回空指针举例开辟20个字节的空间存放 1 2 3 4 5 并输出intmain(){int*p(int*)calloc(5,sizeof(int));//开辟5个大小为4个字节的空间if(pNULL){perror(malloc);return1;}for(inti0;i5;i){*(pi)i1;//*(p i) p[i]}for(inti0;i5;i){printf(%d ,*(pi));}free(p);pNULL;return0;}1.4 reallocrealloc 的函数声明如下void*realloc(void*ptr,size_tsize);作用如果 ptr 为空则开辟 size 个大小的空间单位是字节如果 ptr 不为空则将 ptr 所指向的空间扩张至 size 个大小参数部分ptr 为指向动态开辟空间的指针size 为新空间大小返回值开辟成功返回空间首地址的指针开辟失败返回空指针realloc 在重新分配空间时使用的方法第一种原空间后方的空间余量够扩大到 size 个时则直接向后扩张即可比如说现在已经动态分配了 20B 的内存空间想要扩张至 40B在已分配空间后方还有 20B够扩张到 40B那么就会直接向后扩张图解第二种原空间后方的空间余量不够扩大到 size 个时则需要另找一片空间重新分配比如现在已经动态分配了 20B 的内存空间想要扩张至 40B但是已分配空间后方不够 20B不够扩张到 40B那么就会寻找一片 40B 的空间进行分配将原空间的数据复制到里面返回指向新空间的指针举例开辟20个字节的空间存放 1 2 3 4 5 后将其扩大到 40B再存放 6 7 8 9 10 并输出#includestdlib.h#includestdio.hintmain(){int*p(int*)malloc(sizeof(int)*5);if(pNULL){perror(malloc);return1;}for(inti0;i5;i)//存放1 2 3 4 5{*(pi)i1;//*(p i) p[i]}int*p2(int*)realloc(p,40);if(p2NULL)//检查新空间是否开辟成功{perror(realloc);return1;}pp2;//开辟成功再改变指针指向p2NULL;for(inti5;i10;i){*(pi)i1;}for(inti0;i10;i){printf(%d ,*(pi));}free(p);pNULL;return0;}2 常见的动态内存错误2.1 对NULL指针的使用intmain(){int*p(int*)malloc(INT_MAX*2);*p10;//p若为NULL不能解引用free(p);pNULL;return0;}为了防止这个问题需要对指针进行检查intmain(){int*p(int*)malloc(INT_MAX*2);if(pNULL)//防止空指针问题{perror(malloc);return1;}*p10;//p若为NULL不能解引用free(p);pNULL;return0;}2.2 越界访问intmain(){int*p(int*)malloc(sizeof(int)*5);if(pNULL){perror(malloc);return1;}for(inti0;i5;i)//只有5个元素但是下标遍历到了6{*(pi)i;}free(p);pNULL;return0;}2.3 对非动态开辟的空间进行释放intmain(){intarr[]{1,2,3,4,5};free(arr);//arr不是动态开辟的空间return0;}2.4 对动态开辟的空间重复释放intmain(){int*p(int*)malloc(sizeof(int)*5);if(pNULL){perror(malloc);return1;}free(p);free(p);pNULL;return0;}为了防止这个问题应该在第一次释放后将指针置为空intmain(){int*p(int*)malloc(sizeof(int)*5);if(pNULL){perror(malloc);return1;}free(p);pNULL;free(p);return0;}2.5 释放部分动态开辟的空间intmain(){int*p(int*)malloc(sizeof(int)*5);if(pNULL){perror(malloc);return1;}p;free(p);pNULL;return0;}2.6 忘记释放动态开辟的内存空间intmain(){int*p(int*)malloc(sizeof(int)*5);if(pNULL){perror(malloc);return1;}return0;}3 柔性数组柔性数组是通过结构体来实现的具体实现方法为将结构体的最后一个成员设置为数组该数组前一定要有一个或多个成员变量此数组不设大小structS{inta;intarr[];//柔性数组成员};当结构体内有柔性数组使用 sizeof 在计算类型大小时不会将柔性数组的大小计算入内只会计算柔性数组之前成员的大小因此就可以使用动态分配的方式指定数组的空间大小举例分配大小为 20B 的空间给柔性数组structS{inta;intarr[];//柔性数组成员};intmain(){structS*p(int*)malloc(sizeof(structS)sizeof(int)*5);//先分配柔性数组前成员变量的空间再分配柔性数组的空间if(pNULL){perror(malloc);return1;}free(p);pNULL;return0;}图解如果想要更改柔性数组的大小只需要使用 realloc 即可举例将 20B 的柔性数组变成 40BstructS{inta;intarr[];//柔性数组成员};intmain(){structS*p(int*)malloc(sizeof(structS)sizeof(int)*5);if(pNULL){perror(malloc);return1;}structS*p2(int*)realloc(p,sizeof(structS)sizeof(int)*10);//更改为40Bif(p2NULL){perror(malloc);return1;}pp2;p2NULL;free(p);pNULL;return0;}图解假设后方有空间