当前位置: 首页 > news >正文

C语言中的动态内存分配

在很多场景,数据的大小是在运行时才能确定,编译阶段无法确定数据长度;或者有大块的数据需要存放,但是栈空间不够;或者某些参数需要实现跨函数传递;或者需要实现可变的数据结构。当面临这些问题时,我们往往想到动态分配内存。本文将主要讲在C语言中,动态内存分配的4个常用函数,以及使用注意事项。
一、为什么要用动态内存
栈内存存放局部变量,大小编译期确认,空间很小(通常只有几MB),函数结束自动销毁
堆内存空间大,动态分配,大小运行时确定,但是必须手动管理
原因1:【主要原因】运行时才知道需要多大内存
静态数组写大了浪费内存,写小了会溢出,动态内存要多少给多少
例如:用户输入、读取文件、网络接收的数据,程序跑起来才知道要多少数据,没有办法提前写死。
原因2:突破栈空间限制
栈空间很小,一般就1-8MB左右,大数据不能放在栈上,必须放到堆。
原因3:内存生命周期不受函数作用域限制
栈上的局部变量,函数执行完毕就自动释放了,不能继续函数外使用
动态内存:函数结束,堆内存依然存在,必须手动free才释放
eg:局部数组,函数返回后内存销毁,返回指针就是也指针
原因4:实现可边长数据结构
链表、队列、树、哈希表,全部离不开动态内存。
链表每新增一个节点,就要malloc一块内存节点(没有动态内存,就写不出链表)
二、四种常用动态内存函数
1、四种对比

函数参数内存初始化功能
mallocmalloc(字节数)不初始化(垃圾值)分配指定大小堆内存
calloccalloc(元素个数,每个大小)全部置0分配数组,自动清零
reallocrealloc(旧指针,新总字节)旧数据保留,新增部分不初始化修改已分配内存大小,扩容缩容
freefree(指针)-释放堆内存
malloc和realloc分配的空间生存期,是随进程持续性,不是随代码块持续性。
2、malloc
作用:分配X字节的堆内存,不会初始化内存,里面为随机值。分配成功返回内存首地址,分配失败返回NULL
#include<stdio.h>#include<windows.h>#include<math.h>intmain(){SetConsoleOutputCP(65001);SetConsoleCP(65001);//在堆上申请10个连续int内存空间int*p=(int*)malloc(10*sizeof(int));if(p==NULL){printf("动态内存分配失败\n");}else{printf("动态内存分配成功\n");for(inti=0;i<10;i++){printf("%p,存放的内容%lx\n",&p[i],p[i]);}}free(p);//用完释放p=NULL;// 置空,防止野指针return0;}

运行结果:

malloc分配的内存不会自动初始化,所有元素默认是随机垃圾值,使用前建议手动赋值。
3、calloc
calloc(num,size)
作用:分配num个元素,每个占用size字节,分配完成自动全部初始化为0
和malloc的区别:calloc会清零,malloc不会。

//上面的malloc变为callocint*p=(int*)calloc(10,sizeof(int));

运行结果:

4、realloc
realloc(ptr,new_size)
作用:重新修改已分配好的堆内存,扩容或缩容
ptr:之前得到的指针
newsize:新的总字节数
注意:
如果后面堆空间足够,直接原地扩容,返回原来的地址
如果后面不够,堆找一块全新内存,把旧内容复制过去,释放旧内存,返回新地址
失败返回NULL,原来旧内容不会释放
realloc(ptr,0):长度为0,是把原来的空间释放

#include<stdio.h>#include<windows.h>#include<math.h>intmain(){SetConsoleOutputCP(65001);SetConsoleCP(65001);//在堆上申请10个连续int内存空间,并将内存的首地址赋值给整型指针pint*p=(int*)calloc(5,sizeof(int));int*tmp=(int*)realloc(p,10*sizeof(int));if(p==NULL){printf("动态内存分配失败");}else{printf("-----动态内存分配成功-----\n");for(inti=0;i<5;i++){printf("%p,存放的内容%lx\n",&p[i],p[i]);}if(tmp!=NULL){printf("-----重新分配成功-----\n");p=tmp;for(inti=0;i<10;i++){printf("%p,存放的内容%lx\n",&p[i],p[i]);}}else{printf("-----重新分配失败-----\n");//分配失败,p仍指向旧内存,可以继续使用printf("%p\n",&p);}}free(p);//用完释放p=NULL;// 置空,防止野指针return0;}

运行结果:

注意:realloc直接用原指针接收返回值,失败会导致内存泄漏(例子中直接写p=realloc(p,newsize);如果失败p被赋值为NULL,原内存地址丢失,直接内存泄漏)。
realloc(NULL,n)等价于malloc(n)
5、free释放内存
作用:释放堆内存,还给操作系统
规则
参数必须是malloc、realloc、calloc返回的地址,不能传栈变量地址
free之后,原来的指针变量仍然保存旧地址,变为野指针,建议手动赋值为NULL
不能重复free同一个指针,程序会崩溃
free(NULL)是安全的,什么都不做

三、使用注意事项
1、实际项目大量使用动态内存(malloc、realloc、calloc、free),但是不能无脑使用,滥用会付出巨大代价
内存泄漏:忘记free,程序越跑内存占用越高,长期运行服务直接卡死。
野指针:free之后,继续使用,重复free,直接崩溃
realloc坑点,分配失败处理麻烦
频繁malloc、free会产生内存碎片,长时间运行内存效率下降

所以:
小固定大小缓冲区,优先栈数组,不要malloc
malloc和free尽量配对,谁申请,谁释放
嵌入式设备内存很小,尽量少用动态内存,必要时禁止malloc
2、垃圾内存/内存泄漏

char*p=malloc(10);chara;p=&a;//p本来指向10字节的动态内存分配的空间,现在指向a

上述代码,没有任何指针会指向那段动态内存分配的空间,并且那段空间不会释放,变为垃圾内存(或说内存泄漏)
解决办法:
方案一:p指向其他对象之前先释放

free(p);p=&a;

方案二:p指向其他对象之前,给那段空间找一个索引指针

char*q=p;//后面可以通过q来释放这段空间。p=&a;
http://www.cnnetsun.cn/news/3974303.html

相关文章:

  • 5分钟快速上手:免费开源AI生成平台Open Generative AI完全指南
  • 终极越狱指南:palera1n深度解析与A8-A11设备完整越狱实战
  • Visual Studio中高效配置与优化Eigen库:从入门到性能调优
  • 如何在10分钟内完成AI规范驱动开发全流程:cc-sdd终极指南
  • Fnet 云网安 260810
  • 10分钟极速上手:Hermes WebUI容器化部署与AI助手体验全攻略
  • Linux C/C++开发工具链:从yum、vim到gcc、gdb、Makefile的实战指南
  • 技术人高效平衡术:75天备考与项目开发双线作战指南
  • Steam ROM Manager终极指南:如何批量管理非Steam游戏和模拟器ROM
  • Linux 性能预算有限:先定位瓶颈,再决定优化方向
  • 止损与破局——你的职场生存策略总框架
  • Prompt驱动前端NLP:基于ES6模块化构建可组合文本推理能力
  • 游戏出海热潮下,海外数字媒体留学生如何敲开米哈游的大门?
  • 终端 DLP 数据防泄露系统后台日志模块与风险统计功能深度拆解
  • 医院后勤工单管理系统 品牌选型报告
  • 2026 香港居屋定制收纳哪家设计更实用?
  • SERP 客户端 SDK 版本管理:接口改了怎么不炸
  • UDP协议特性解析与Wireshark实战应用
  • 【会议征稿通知 | 桂林航天工业学院、南宁师范大学联合主办 | IEEE出版 | EI 、Scopus稳定检索】第二届图像、信号处理与机器学习国际学术会议(ISPML 2026)
  • 极简产品设计:先拆开用户真正需要完成的那一步
  • ComfyUI-WanVideoWrapper深度解析:如何构建高效AI视频生成工作流
  • 终极指南:如何使用palera1n工具完成iOS设备越狱
  • 题解:洛谷 P2233 [HNOI2002] 公交车路线
  • 从源码到exe:Crypter项目结构与关键组件解析
  • 卡丁快跑的跟踪方式规则确认
  • 如何快速部署Xash3D FWGS:面向开发者的完整实战指南
  • Snap! 可视化编程完整指南:从入门到精通的终极教程
  • AI 数据库内核优化与智能查询计划生成:先收紧输入、状态与退出边界
  • CSTR串联模型在污水处理厂二沉池模拟中的应用
  • 文献综述写到崩溃?5类AI工具深度横评:毕业之家、知网研学、万方到底怎么选?