动态内存管理

简介: 动态内存管理

一、为什么要有动态内存分配

       我们在写代码时,编译器都会自动为我们分配空间,但会有这么两个特点:

        空间开辟⼤⼩是固定的。

       数组在申明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整。

       但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间⼤⼩在程序运⾏的时候才能知道,那数组的编译时开辟空间的⽅式就不能满⾜了。

        C语⾔引⼊了动态内存开辟,让程序员⾃⼰可以申请和释放空间,就⽐较灵活了。

二、动态内存开辟的函数

       2.1 malloc函数

void* malloc (size_t size);

       这个函数向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针。

        如果开辟成功,则返回⼀个指向开辟好空间的指针。

       如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查。

        返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者⾃ ⼰来决定。

       如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器。  

        2.2 calloc函数

void* calloc (size_t num, size_t size);

       函数的功能是为 num 个⼤⼩为 size 的元素开辟⼀块空间,并且把空间的每个字节初始化为0。

       与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。

       2.3 realloc函数

void* realloc (void* ptr, size_t size);

        realloc函数的出现让动态内存管理更加灵活。

        有时会我们发现过去申请的空间太⼩了,有时候我们⼜会觉得申请的空间过⼤了,那为了合理的时 候内存,我们⼀定会对内存的⼤⼩做灵活的调整。那 realloc 函数就可以做到对动态开辟内存⼤ ⼩的调整。

       realloc在调整内存空间的是存在两种情况:

       情况1:原有空间之后有⾜够⼤的空间

       情况2:原有空间之后没有⾜够⼤的空间

      情况1

       当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化。

       情况2

       当是情况2 的时候,原有空间之后没有⾜够多的空间时,扩展的⽅法是:在堆空间上另找⼀个合适⼤⼩ 的连续空间来使⽤。这样函数返回的是⼀个新的内存地址。

三、内存释放函数

       学习完内存开辟函数后,我们随后会来学习内存释放函数。那我们为什么要学习内存释放函数呢?内存开辟函数就是向内存中借一块空间,俗话说:有借有还。所以,我们要来学习内存释放函数来进行归还。所以在学习前记住一句话:只要开辟就要释放。

void free (void* ptr);

       内存释放函数为free函数,如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。

       如果参数 ptr 是NULL指针,则函数什么事都不做。

四、柔性数组

       柔性数组是什么?相信看到这你有点小懵,难道会柔道的数组称之为柔性数组?非也。柔性数组为结构体中定义的处于结构体最后一个成员的数组(最好不要定义其大小,有的编译器会报错)。

1. typedef struct s
2. {
3.  int a;
4.  int arr[];
5. };

       柔性数组的特点:

       柔性数组的前面必须包含其他结构体成员。

       sizeof求其结构体大小时不会包含柔性数组的大小。

       使用malloc为柔性数组开辟空间时,要大于结构体的大小以符合柔性数组的期待。

        用法如下:

1. 
2. #include<stdio.h>
3. typedef struct s
4. {
5.  int a;
6.  int arr[];
7. }type_a;
8. int main()
9. {
10.   int a = 0;
11.   type_a* p = (type_a*)(malloc(sizeof(type_a) + 100 * sizeof(int)));
12.   p->a = 100;
13.   for (int i = 0; i < 100; i++)
14.   {
15.     p->arr[i] = i;
16.   }
17.   free(p);
18.   p = NULL;
19.   return 0;
20. }
21. 
22.

五、 经典例题

1. #include<stdio.h>
2. #include<stdlib.h>
3. void GetMemory(char* p)
4. {
5.  p = (char*)malloc(100);
6. }
7. void Test(void)
8. {
9.  char* str = NULL;
10.   GetMemory(str);
11.   strcpy(str, "hello world");
12.   printf(str);
13. }

       以上代码运行会有什么后果?

       本题意图为为str开辟出一块空间,对吧?但是,在函数中p为局部变量,运行结束时会销毁,所以,它的地址传不回来,就会开辟失败。但,即使开辟成功,仍有问题,这是为什么呢?咱们在开始时,说过了要有借有还,所以应该要对其进行内存释放,否则,会造成内存泄漏。

1. #include<stdio.h>
2. #include<stdlib.h>
3. void Test(void)
4. {
5.  char* str = (char*)malloc(100);
6.  strcpy(str, "hello");
7.  free(str);
8.  if (str != NULL)
9.  {
10.     strcpy(str, "world");
11.     printf(str);
12.   }
13. }

        以上代码运行会有什么后果?

       在str开辟完空间后,又对其释放,那str能打印出来吗?答案是:不一定。为什么?内存不是没了吗?那里面存放的理应没了呀?对吧。其实,你可以这样理解:你在酒店开了个房间,第二天为了赶火车,不小心把身份证落下了,如果此时房间还没有被打扫,你还能在原位置找到,对吧?打扫了就不能在原位置找到了对吧?理解了我举得例子,相信你就理解了打印结果的情况。

       完!

相关文章
|
4月前
|
消息中间件 Java Kafka
在 OpenAI 打造流处理平台:超大规模实时计算的实践与思考
本文整理自 OpenAI 基础设施团队的 Shuyi Chen 和 Joey Pereira 在 Current 2025 伦敦会议上的演讲 ”Building a Stream Processing Platform at OpenAI“,主要演讲内容为: OpenAI 的流式基础设施 构建流处理平台的动机及遇到的挑战; OpenAI 的整体架构及深入解读 OpenAI 业务用例以及平台未来的演进方向
219 2
在 OpenAI 打造流处理平台:超大规模实时计算的实践与思考
|
9月前
|
存储 算法 fastjson
火点监测:Nasa高分卫星接入
NASA(美国国家航空航天局)是美国联邦政府的一个独立机构,负责国家的航空航天研究和探索任务。NASA成立于1958年,其使命是探索太空并推动科学技术的发展。NASA的主要任务包括研究地球和太空的物理特性、开发和测试航空航天技术、进行太空探索和科学研究,以及促进航空航天技术的应用和技术转移。这里使用其开发的系统firms(火灾资源管理系统),通过Http请求获取数据来实现火点的监测,帮助需要实现相关功能,有类似开发任务的朋友。
330 6
|
前端开发 JavaScript API
HarmonyOS:ArkTS 显式动画 animateTo 自学指南
本文深入解析了 ArkTS 中的 `animateTo` 全局显式动画接口,帮助开发者掌握其使用方法。文章从接口概述、参数详解到使用注意事项,结合实际示例代码,全面展示了如何通过配置 `AnimateParam` 对象实现流畅的动画效果。内容涵盖属性动画、布局变化及组件转场等场景,并强调不同版本的支持特性。适合初学者系统学习,也供进阶开发者参考优化动画体验。希望本文能助你快速上手 `animateTo`!
664 7
|
消息中间件 存储 缓存
招行面试:如何让系统抗住双十一 预约抢购活动?10Wqps级抢购, 做过吗?
本文由40岁老架构师尼恩撰写,针对一线互联网企业如得物、阿里、滴滴等的面试题进行深度解析。文章聚焦于如何设计系统以应对大促活动中的预约抢购场景,涵盖从预告到支付的完整流程。尼恩通过系统化、体系化的梳理,帮助读者提升技术实力,轻松应对高并发挑战,并提供了详细的架构设计和解决方案。文中还分享了《尼恩Java面试宝典》等资源,助力求职者在面试中脱颖而出,实现“offer直提”。更多内容及PDF资料,请关注公众号【技术自由圈】获取。
|
机器学习/深度学习 人工智能 算法
基于YOLOv8的钢铁缺陷实时检测系统【训练和系统源码+Pyside6+数据集+包运行】
基于YOLOv8的钢铁缺陷实时检测系统,通过1800张图片训练,开发了带GUI界面的检测系统,支持图片、视频和摄像头实时检测,提高生产效率和产品质量。系统基于Python和Pyside6开发,具备模型权重导入、检测置信度调节等功能。项目代码、数据集可通过特定链接获取。
604 1
基于YOLOv8的钢铁缺陷实时检测系统【训练和系统源码+Pyside6+数据集+包运行】
|
传感器 运维 供应链
数字孪生与物流:智能供应链管理
数字孪生技术通过在数字世界中创建物理实体的虚拟模型,实时反映其状态和性能,优化物流系统的运作和管理。本文探讨了数字孪生在智能仓储、运输调度、包装设计、设备维护及基础设施规划等物流领域的应用,展示了其在提高供应链效率、降低成本、增强韧性和推动智能化发展方面的优势,同时也指出了面临的挑战和未来的发展方向。
|
机器学习/深度学习 数据挖掘 PyTorch
🎓PyTorch深度学习入门课:编程小白也能玩转的高级数据分析术
踏入深度学习领域,即使是编程新手也能借助PyTorch这一强大工具,轻松解锁高级数据分析。PyTorch以简洁的API、动态计算图及灵活性著称,成为众多学者与工程师的首选。本文将带你从零开始,通过环境搭建、构建基础神经网络到进阶数据分析应用,逐步掌握PyTorch的核心技能。从安装配置到编写简单张量运算,再到实现神经网络模型,最后应用于图像分类等复杂任务,每个环节都配有示例代码,助你快速上手。实践出真知,不断尝试和调试将使你更深入地理解这些概念,开启深度学习之旅。
320 1
|
存储 安全 算法
信息安全:认证技术原理与应用.
信息安全:认证技术原理与应用.
1011 7
|
运维 Kubernetes 监控
容器服务ASK初评
【8月更文挑战第12天】容器服务ASK初评
631 3
|
Kubernetes 安全 API
Kubernetes系统安全-认证(Authentication)
文章主要介绍了Kubernetes系统中的安全认证机制,包括API服务器的访问控制、认证、授权策略和准入控制,以及如何使用kubeconfig文件和创建自定义用户与服务账号。
4699 0
Kubernetes系统安全-认证(Authentication)