【C语言】-动态内存管理

张开发
2026/4/8 18:50:02 15 分钟阅读

分享文章

【C语言】-动态内存管理
个人主页深邃-❄️专栏传送门《C语言》《数据结构》Gitee仓库《C语言》《数据结构》目录为什么要有动态内存分配malloc和freemallocfree用法示例申请失败静态数组 vs 动态内存分配callocrealloc用法示例realloc 直接申请空间常见的动态内存的错误对NULL指针的解引用操作对动态开辟空间的越界访问对非动态开辟内存使用free释放使用free释放⼀块动态开辟内存的⼀部分对同⼀块动态内存多次释放动态开辟内存忘记释放内存泄漏C/C中程序内存区域划分为什么要有动态内存分配静态申请intval20;//在栈空间上开辟四个字节chararr[10]{0};//在栈空间上开辟10个字节的连续空间空间开辟大小是固定的。数组在申明的时候必须指定数组的⻓度数组空间⼀旦确定了大小不能调整C语言引入了动态内存开辟让程序员自己可以申请和释放空间就比较灵活了malloc和freemallocC语言提供了⼀个动态内存开辟的函数void*malloc(size_tsize);//C语⾔提供了⼀个动态内存开辟的函数功能向内存的堆区申请⼀块连续可用的空间并返回指向这块空间的起始地址。• 如果开辟成功则返回这块空间的起始地址。• 如果开辟失败则返回⼀个 NULL 指针因此malloc的返回值⼀定要做检查。• 返回值的类型是 void* 所以malloc函数并不知道开辟空间的类型具体在使用的时候使用者自己来决定。• 如果参数 size 为0malloc的⾏为是标准是未定义的取决于编译器。freeC语言提供了另外⼀个函数free专门是用来做动态内存的释放和回收的函数原型如下voidfree(void*ptr);//C语⾔提供了另外⼀个函数free专⻔是⽤来做动态内存的释放和回收的函数原型如下free函数⽤来释放动态开辟的内存。• 如果参数 ptr 指向的空间不是动态开辟的那free函数的⾏为是未定义的。• 如果参数 ptr 是NULL指针则函数什么事都不做。用法示例两者的用法像公式一样几乎任何场景下都是一样的malloc和free都声明 stdlib.h头⽂件中。用法如下#includestdio.h#includestdlib.hintmain(){//申请40个字节int*p(int*)malloc(10*sizeof(int));//判断是否开辟成功if(pNULL)//失败{perror(malloc 错误);return1;}//开辟成功了//使用这块空间了for(inti0;i10;i){p[i]i1;//注意不要修改p地址否则free会释放失败}for(inti0;i10;i){printf(%d ,p[i]);}//当不再使用这块空间的时候主动还回去free(p);pNULL;return0;}申请失败当大小过于大时就会失败 例如2 * INT_MAX静态数组 vs 动态内存分配之前我们或许否有疑问为什么数组的大小不能是变量要理解这个问题我们需要先区分两种内存分配方式以及编程语言对数组的设计逻辑1.在 C/C 这类偏底层的语言中静态数组直接声明在栈上的数组的大小必须是编译期常量而不能是变量核心原因是 栈内存的分配是在编译阶段确定的编译器需要在编译时就知道数组的准确大小才能为其预留固定的栈空间。2. 变量的值是运行阶段才确定的程序运行时变量的值可能随时变化编译器无法提前预知因此无法为 “大小不确定”的数组预留栈空间。其实我们想要的数组的大小是变量的万能数组其实就是动态内存管理intm0;scanf(%d,m);//20intarr[m];//有的编译器支持有的不支持m一旦确定数组的大小是不能变的vs2022上的报错信息而且还有calloc和realloc 可以更改大小更加的万能那让我们了解一下calloc和realloccallocC语⾔还提供了⼀个函数叫 calloc calloc 函数也⽤来动态内存分配。原型如下void*calloc(size_tnum,size_tsize);• 函数的功能是为 num 个大小为 size 的元素开辟⼀块空间并且把空间的每个字节初始化为0。• 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0callocmallocmemset#includestdio.hintmain(){//申请10个整型的空间//int*p (int*)malloc(10 * sizeof(int));int*p(int*)calloc(10,sizeof(int));if(pNULL){perror(calloc);return1;}//使用inti0;for(i0;i10;i){printf(%d\n,p[i]);}//释放空间free(p);pNULL;return0;}reallocrealloc函数的出现让动态内存管理更加灵活。realloc 函数就可以做到对动态开辟内存大小的调整。函数原型如下void*realloc(void*ptr,size_tsize);• ptr 是要调整的内存地址• size 调整之后新大小单位是字节• 返回值为调整之后的内存起始位置。• 这个函数调整原内存空间大小的基础上还会将原来内存中的数据移动到新的空间。• realloc在调整内存空间的是存在两种情况◦ 情况1原有空间之后有足够大的空间◦ 情况2原有空间之后没有足够大的空间情况1当是情况1 的时候要扩展内存就直接原有内存之后直接追加空间原来空间的数据不发⽣变化。情况2当是情况2 的时候原有空间之后没有⾜够多的空间时扩展的⽅法是在堆空间上另找⼀个合适⼤⼩的连续空间来使⽤。这样函数返回的是⼀个新的内存地址。用法示例intmain(){//申请一块空间用来存放1~5的数字int*p(int*)malloc(5*sizeof(int));if(pNULL){perror(malloc);return1;}//使用内存空间inti0;for(i0;i5;i){p[i]i1;}//继续存放6~10//空间不够了需要增容int*p2(int*)realloc(p,6*sizeof(int));if(p2NULL){perror(realloc);free(p);pNULL;return1;}pp2;//接下来继续可以使用p来维护新的空间for(i5;i10;i){p[i]i1;}free(p);pNULL;return0;}realloc 直接申请空间intmain(){int*p(int*)realloc(NULL,40);//malloc(40)//...return0;}常见的动态内存的错误对NULL指针的解引用操作没有对malloc calloc realloc 的返回值做判断voidtest(){int*p(int*)malloc(INT_MAX);*p20;//如果p的值是NULL就会有问题free(p);}对动态开辟空间的越界访问intmain(){int*p(int*)malloc(5*sizeof(int));if(pNULL){perror(malloc);return1;}//inti0;for(i0;i10;i)//当i5的时候就越界访问了{p[i]i1;}free(p);pNULL;return0;}对非动态开辟内存使用free释放intmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};int*parr;//使用//...free(p);//free只能释放malloc,calloc,realloc申请的空间pNULL;return0;}使用free释放⼀块动态开辟内存的⼀部分intmain(){int*p(int*)malloc(10*sizeof(int));if(pNULL){perror(malloc);return1;}inti0;for(i0;i5;i){*pi1;p;}free(p);//free释放空间的时候一定要给这块空间的起始位置pNULL;return0;}对同⼀块动态内存多次释放intmain(){int*p(int*)malloc(10*sizeof(int));if(pNULL){perror(malloc);return1;}//使用free(p);//...free(p);pNULL;return0;}但是如果我们有个好习惯每次free之后都NULL一下这个问题不会存在因为free(NULL)会当作什么都没干free(p);pNULL;//free两次也没问题free(p);pNULL;动态开辟内存忘记释放内存泄漏voidtest(){int*p(int*)malloc(100);if(NULL!p){*p20;}}intmain(){test();while(1);return0;}程序死循环一直结束不了内存无法回收忘记释放不再使⽤的动态开辟的空间会造成内存泄漏。切记动态开辟的空间⼀定要释放并且正确释放。C/C中程序内存区域划分C/C程序内存分配的几个区域1. 栈区stack在执⾏函数时函数内局部变量的存储单元都可以在栈上创建函数执⾏结束时这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中效率很⾼但是分配的内存容量有限。 栈区主要存放运⾏函数⽽分配的局部变量、函数参数、返回数据、返回地址等。《函数栈帧的创建和销毁》2. 堆区heap⼀般由程序员分配释放 若程序员不释放程序结束时可能由OS操作系统回收 。分配⽅式类似于链表。3. 数据段静态区static存放全局变量、静态数据。程序结束后由系统释放。4. 代码段存放函数体类成员函数和全局函数的⼆进制代码。感谢大佬们三连你的鼓励就是对我创作的激励 \color{purple}{感谢大佬们三连你的鼓励就是对我创作的激励}感谢大佬们三连你的鼓励就是对我创作的激励

更多文章