Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?

作者头像
蒙奇D索隆
发布于 2024-12-20 02:14:35
发布于 2024-12-20 02:14:35
10700
代码可运行
举报
运行总次数:0
代码可运行

动态内存管理——动态函数(malloc、free)的使用

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_内存空间
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_内存空间

导言

大家好,很高兴又和大家见面了!!!

对于一门计算机语言来说,它只是我们与计算机沟通的一道桥梁,而不同的语言就像不同的方言一样,每一种方言都有自己独特的表达方式,在计算机语言中也是一样,每一种计算机语言都有独属于自己的表达方式。

在C语言中,我们已经学习了条件语句、循环语句、函数、数组、操作符、指针、结构体这些C语言的基础语法,而今天我们要介绍的动态内存管理则是C语言中我们必须要掌握的与内存相关的基础知识。

那什么是动态内存管理?如何实现动态内存管理?则会是我们在今天的内容中重点介绍的内容。

一、动态内存管理

1.1 什么是动态内存管理?

要理解什么是动态内存管理,这里我们就需要将其拆解成两个元素——动态与内存管理:

  • 动态:如字面意思一样,能够动,也就是可以改变
  • 内存管理:如字面意思一样,就是对内存进行管理。

因此我们将动态内存管理就可以理解为对可以改变的内存进行管理。

1.2 为什么要有动态内存管理?

为了搞清楚为什么要有动态内存管理,下面我们就来看一个实例:

现有一家平均日流量为300的奶茶店,为了能够方便到店的顾客进行点餐与预约以及外卖,因此需要有一个完善的下单系统。该奶茶店的客流量峰值曾经达到过500左右,在淡季时,也曾出现过100左右的客流量。

当你拿到这个项目时,你会选择如何来对这个订单系统进行设计呢?

通过前面的知识我们知道,一个订单系统无非就是需要记录以下信息:

  • 订单编号
  • 订单类型——堂食、打包、外卖
  • 商品名称
  • 客户备注

通过前面所学的知识我们知道,对于这种复杂的事物的描述我们可以通过结构体来实现,而对于同一类型的数据,我们则可以通过数组来进行存储,因此我们不难想到可以通过结构体类型的数组来存储订单,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//订单系统
typedef enum type {
	DINI_IN,
	PACK,
	TAKEAWAY
}type;
typedef struct Tea {
	int number;//订单编号
	type order;//订单类型
	char name[20];//商品名称
	char remark[20];//备注
}Tea;

void test1() {
	Tea t[] = { 0 };
}

那现在问题来了,数组的大小定多少合适呢?从这个例子中的描述来看,该奶茶店的客流量起伏还是比较大的,因此现在就会出现两种情况:

  • 当我们将数组的大小定的太大时,若该店的客流量一直处于最低的水平,那么势必就会造成大量的空间浪费的现象;
  • 当我们将数组的大小定的太小时,如该店的客流量在短时间内达到了峰值,甚至是超过了峰值,那势必就会导致后续的顾客无法点单的现象

从这个例子中我们就能够体会到,如果仅仅依靠前面所学的知识,并不能很好的解决这个情况,这也是因为不管是创建变量还是创建数组,都仅仅是在内存空间中申请的一块固定大小且不可改变的空间。

而在实际的问题中,并不可能所有的事情都是最理想的情形,因此我们就需要一种可以对内存的大小根据实际情况进行调节的方式——动态内存管理。

1.3 如何实现动态内存管理?

动态内存管理主要涉及到两个功能:

  • 申请内存空间
  • 释放内存空间

而这些功能在C语言中是通过对应的动态内存函数进行实现的:

  • 3个库函数来实现申请内存空间的操作: malloccallocrealloc
  • 1个库函数来实现释放内存空间的操作: free
  • 使用这些函数,我们需要引用头文件:stdlib.h

现在有朋友就会好奇了,当我们在创建变量或是创建数组时,不是就已经在内存中申请了一块空间吗?为什么还可以通过这些库函数来实现动态的内存管理呢?

对于这个问题,目前我们可以理解为,我们通过创建一个指向我们申请的内存空间的指针,然后再借由这个指针与上面的这4种库函数来完成整个内存的申请与释放的过程。

那具体应该如何操作,下面就让我来一起探讨一下吧!!!

二、malloc函数

我们要介绍的第一个函数是malloc函数,谐音读法——马尔洛克; 为了更好的介绍malloc函数,下面我们借助MSDN来看一下malloc函数的介绍:

2.1 函数介绍

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_c函数_02
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_c函数_02

从函数的介绍中,我们可以将它的大致用法总结为以下几点:

  • malloc函数参数为申请内存空间的大小;
  • malloc函数的返回值为无类型指针;
  • malloc函数引用的头文件是stdlib.h和malloc.h;
  • malloc的返回值指向其它类型的指针时,需要对malloc的返回值进行强制类型转换;
  • malloc申请的内存空间不足时,返回空指针;
  • 我们需要始终检查malloc的返回值是否为空指针;

现在我们已经初步了解了malloc函数的用法,但是它具体应该如何使用呢?目前我们还不是很清楚,下面我们就来探讨一下malloc函数的使用方式;

2.2 malloc的使用

要想使用malloc函数,我们就需要先弄清楚函数的三要素,下面我们来看一下该函数的原型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void *malloc( size_t size );

可以看到,函数就一个参数,参数类型为无符号整型,结合前面的函数介绍,这里我们不难推测,该函数的参数是传入的需要申请的空间的大小,单位是字节,也就是说当我们要申请10个整型空间的话,我们就需要传入参数:10*sizeof(int)

函数的返回类型是一个无符号指针类型,也就是说,函数的返回值是需要一个指针类型的变量才能接收,结合前面的函数介绍,那我们就不难推测,该函数的返回值的类型可以根据具体接收的指针类型来进行调整,如我们通过整型指针来接收,那么我们就可以通过强制类型转换将其转成整型指针类型。

但是我们需要注意的是,函数的介绍中有交代——当malloc申请的内存空间不足时,即申请空间失败时,返回空指针,我们需要时钟检测malloc的返回值是否为空指针。

也就是说在使用malloc函数申请空间时,因为存在申请失败的可能性,所以我们在使用接收返回值的指针前,需要对指针进行判空操作,来避免出现对空指针进行解引用等错误操作行为。

现在我们就可以尝试着使用一下malloc函数,如下所示:

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_动态内存_03
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_动态内存_03

这里我们尝试着申请了一个整型大小的空间,从对函数的返回值的判断来看,此时我们成功申请了空间。下面我们再来测试一下可能出现申请失败的情况,如下所示:

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_内存空间_04
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_内存空间_04

可以看到,此时我们想要申请的空间太大了导致空间申请失败了,所以函数返回值为空指针。

当然,并不是说一定是要申请很大的内存空间才有可能申请失败,只有当我们要申请的空间大小超过了内存剩余空间大小时,才会申请失败。这时的问题就来了,因为内存剩余空间大小我们并不知道,所以当我们申请空间时,我们并不能够确定是否超过了剩余空间的大小,所以我们才需要在进行空间申请后对返回值进行一下判空操作。

不知道大家还记不记得assert断言以及perror这两个函数,在进行返回值判空操作时,我们是可以借助这两个函数其中之一来完成的,如下所示:

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_c函数_05
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_c函数_05

可以看到,当我们通过perror来进行判断时,函数能够很好的指出此时发生的错误,并且不会影响程序的运行,因此在空间申请失败时,我们需要借助转向语句来终止函数的继续运行;

而通过assert进行断言时,如果断言失败后,程序会立即被终止,

注:对于malloc函数返回值的判空操作,不管是perror还是assert都是很好的判断工具。 在实际开发中,还是建议大家使用perror来进行判断;在平时的leetcode刷题、练习中,这两种方式都是可以的。

2.3 空间的释放

现在我们已经知道了如何通过malloc函数来申请空间了,那下面问题就来了,如果我们申请的这个空间我们不想要了,应该如何处理呢?

在前面的学习中,对于空间的处理这个问题我们从来没有关注过,因为不管是之前学的创建变量还是创建数组空间,这些空间都会随着函数栈帧的销毁而同步的被释放。

在指针篇章中我们有提到过野指针的成因,其中有一条就说的是返回创建的临时指针变量指向的空间地址,如下所示:

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_动态内存_06
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_动态内存_06

在上例中,对于指针pa来说,它是在函数func()中创建的临时指针,当完成函数调用后,该指针指向的内存空间已经被释放,此时我们通过临时指针ret来接收该地址时,ret就变成了一个野指针,因此我们才会看到ret指向的空间中的值因为调用了一次printf函数就发生了改变的情况;

那如果我们是通过malloc函数申请的空间又会怎样呢?如下所示:

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_c函数_07
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_c函数_07

在这次的测试中,我们在func函数中通过malloc申请了一块空间,并且通过指针pa指向这块空间,最后我们再将变量a的值存入了该空间中;

在测试函数中我们再一次来以同样的方式输出func函数的返回值时,此时可以看到,指针ret指向的空间的值不会再因为调用printf函数而发生改变,也就是说,ret指向的空间不再是野指针。

从这个测试结果我们可以得到以下信息:

  1. malloc申请的空间不会随着函数栈帧的销毁而释放
  2. 函数返回指向由malloc申请的空间的指针时,不会照成野指针的问题

那既然这个空间不会随着函数栈帧的销毁而释放,那我们又应该如何来释放这个空间呢?

这个问题的答案就是我们下面要介绍的函数——free,我们一起接着往下看;

三、free函数

对于由动态内存函数申请的空间,它的释放主要有两种方式:

  1. 由程序员借助free函数主动释放
  2. 在程序结束时,由操作系统主动回收

free函数在动态内存函数中的主要功能就是用来释放内存空间,那它具体应该如何使用呢?下面我们一起来看一下free函数的介绍;

3.1 函数介绍

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_c函数_08
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_c函数_08

从函数介绍中我们可以提炼以下结点信息:

  1. free函数只能释放由callocmallocrealloc申请的内存空间
  2. free函数在进行释放内存空间时,释放的空间大小与申请的空间大小一致
  3. free函数释放的内存为空指针时,函数会直接返回,不进行任何操作
  4. free函数释放的不是由callocmallocrealloc申请的内存空间时,会报错

3.2 free的使用

和之前一样,要探讨函数的使用,我们首先需要来认识一下函数的原型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void free( void *memblock );

从函数的原型中可以看到,free函数是没有返回值的,并且free函数的参数是一个 void* 类型的指针。

结合前面的介绍来看,该参数就是指向由malloccallocrealloc这些函数返回的内存空间的指针。也就是说,当我们在需要释放申请的内存空间时,我们便可以通过将指针作为参数传给free函数来进行空间的释放,如下所示:

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_内存空间_09
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_内存空间_09

从这次测试中可以看到,当我们通过free将指针ret指向的内存空间释放后,此时指针指向的空间存储的内容变成了随机值,也就是说此时的ret变成了一个野指针。

既然是野指针,那么为了避免在后续的使用中对该野指针进行调用,因此我们最好养成在完成释放内存后,将该指针置为空指针,如下所示:

【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_动态内存_10
【C语言必学知识点七】你知道如何实时改变申请好的内存空间的大小吗?你知道什么是动态内存管理吗?你知道如何进行动态内存管理吗?_动态内存_10

3.4 小结

现在我们就介绍完了动态内存管理的一个基本操作:

  • 通过malloc来申请空间
  • 通过free来释放空间

从前面的介绍中,我们大致可以将动态内存管理总结为以下几点:

  1. 动态内存管理就是通过动态函数来完成空间的申请与释放
  2. 通过malloc申请的空间跟随函数的销毁而释放,只能通过free函数完成释放
  3. malloc能够主动在内存空间中申请指定字节大小的空间:
  • malloc函数申请空间成功时,会返回指向该空间的指针
  • malloc函数申请空间失败时,会返回空指针
  1. malloc完成空间申请后,我们需要及时对malloc函数的返回值进行判空操作
  2. free函数只能够释放由malloccallocrealloc申请的空间
  3. free函数的参数为空指针时,free函数不会执行任何操作

结语

今天的内容到这里就全部结束了,在下一篇内容中我们将介绍《callocrealloc函数的使用》的相关内容,大家记得关注哦!如果大家喜欢博主的内容,可以点赞、收藏加评论支持一下博主,当然也可以将博主的内容转发给你身边需要的朋友。最后感谢各位朋友的支持,咱们下一篇再见!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
C语言详解(动态内存管理)1
本篇文章将介绍C语言中除指针和结构体外又一重要的内容——动态内存管理 在C语言中,我们更多的需要手动分配和释放内存,这意味着我们必须正确地管理内存,以避免内存泄漏、内存溢出和其他内存错误,这些错误可能导致程序崩溃或安全漏洞。因此,了解内存管理是编写高质量、高效率和健壮性程序的重要部分。
_小羊_
2024/10/16
1250
C语言详解(动态内存管理)1
C语言之动态内存管理(快点进来!!!)
但对于空间的需求,我们有的时候并不知道,有可能空间开大了造成了浪费,也有可能空间开小了造成栈溢出,这样我们就需要一个动态的内存管理让我们需要多少内存的时候开辟多少。
用户11036582
2024/03/21
1430
C语言之动态内存管理(快点进来!!!)
C语言之动态内存管理
然而,在实际应用中,我们需要向内存中申请动态(大小可变)的内存空间,因此本文向大家介绍有关于动态内存空间的知识。
摘星
2023/04/28
5980
C语言之动态内存管理
C语言-动态内存管理
假设我们要写一个简单的学生成绩管理系统。在这个系统中,我们需要存储学生的成绩信息,但是我们并不知道会有多少个学生的数据需要存储。如果我们一开始就定义一个很大的数组来存储成绩,可能会浪费大量的内存空间;而如果定义的数组过小,又无法满足实际需求。那我们有什么办法来解决这种问题呢?”
LonlyMay
2024/11/21
1140
C语言-动态内存管理
【C语言必学知识点七】你知道在动态内存管理中存在的内存泄露问题吗?遇到内存泄露时应该如何处理?今天跟你好好介绍一下如何正确使用calloc与realloc!!!
按理来说,借助malloc与free就已经能够实现动态内存的申请和释放了,为什么还会存在calloc与realloc这两个函数呢?他们又有什么作用呢?他们又应该如何使用呢?在今天的内容中,我们将会对这些问题进行一一的探讨,下面我们就一起进入今天的内容吧!!!
蒙奇D索隆
2024/12/20
2100
【C语言必学知识点七】你知道在动态内存管理中存在的内存泄露问题吗?遇到内存泄露时应该如何处理?今天跟你好好介绍一下如何正确使用calloc与realloc!!!
C语言---动态内存管理
• 数组在申明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整,但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间⼤⼩在程序运⾏的时候才能知道,那数组的编译时开辟空间的⽅式就不能满⾜了。
Undoom
2024/09/23
1260
C语言---动态内存管理
【c语言】动态内存管理
我们在定义一个数组的时候,这个数组的大小就是固定的,一旦确定了数组的大小,未来就不能再调整。而c语言中,提供了动态内存开辟,我们就可以自由地申请或者释放空间,更加灵活。
ephemerals__
2024/10/24
1650
【c语言】动态内存管理
动态内存管理基础详解
但是对于空间的需求,不仅仅是上述的情况。有时我们需要的空间大小在程序运行的时候才知道,
用户11316056
2024/10/16
1070
动态内存管理基础详解
C语言进阶(十二) - 动态内存管理
void* malloc(size_t size); 头文件<stdlib.h>
怠惰的未禾
2023/04/27
5970
C语言进阶(十二) - 动态内存管理
【C语言】动态内存管理(heap)
4.补充:C语言是可以创建变长数组的(也就是柔性数组),c99增加了这种语法标准,但现在还是有许多的编译器不支持这种标准
举杯邀明月
2023/04/12
7620
【C语言】动态内存管理(heap)
C语言:(动态内存管理)
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间⼤⼩在程序运⾏的时候才能知 道,那数组的编译时开辟空间的⽅式就不能满⾜了。 C语⾔引⼊了动态内存开辟,让程序员⾃⼰可以申请和释放空间,就⽐较灵活了。
逆向-落叶
2024/10/28
1160
C语言:(动态内存管理)
【C语言】动态内存管理
但是有时候我们需要的内存空间只有在程序运行时才能知道,那上面开辟空间的方式就不合适了。
云边有个稻草人
2024/10/21
1110
【C语言】动态内存管理
C语言:动态内存管理
但是有些时候我们对于空间的需求并不仅仅满足于此,可能我们需要的空间大小是在函数运行时才能够知道,那么数组编译时开辟的空间无法满足我们的需求。可能我们希望空间可以不那么快就被释放,那么在栈区上开辟空间也无法满足我们的要求。
小陈在拼命
2024/02/17
1730
C语言:动态内存管理
【C语言】动态内存管理及相关笔试题
   我们之前已经学过一些开辟内存的方法,就是创建变量时,操作系统给我们分配的空间,而内存大致分为以下3个大部分,如图:
TANGLONG
2024/10/15
1180
【C语言】动态内存管理及相关笔试题
c语言动态内存管理
动态内存分配为我们提供了很大的便利,如果我们想要一块自定的内村大小,可以通过动态内存管理来实现,从而提升了代码的灵活性,之前我们学习的空间开辟一共两种,
用户11367247
2024/11/20
970
c语言动态内存管理
C语言动态内存管理
2.在声明数组的时候,必须指定数组长度以及数组的元素个数,并且以后不能改变数组的长度。
用户11375356
2024/11/22
1240
C语言动态内存管理
C语言——动态内存管理
但是上述的开辟空间的方式有两个特点: 1. 空间开辟大小是固定的。 2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
小李很执着
2024/06/15
1230
C语言——动态内存管理
动态内存管理(超详细!)
大家在此前的C语言学习中已经知道,我们要定义一个值,首先要为它在内存空间上开辟一个空间,通常情况下我们用这种方式来开辟:
ahao
2024/03/19
1570
动态内存管理(超详细!)
【C语言】动态内存管理
但是这样开辟的空间有两个特点: ①空间开辟的大小是固定的 ②数组长度大小不能改变 这样我们引入动态内存开辟,就可以实现我们自己申请和释放空间
s-little-monster
2024/06/06
1270
【C语言】动态内存管理
动态内存管理
如上图,malloc函数被用来申请10个整形大小的空间,malloc函数的返回类型是void*,因为malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来定义。因此我们需要对他进行强转,然后赋给p即可使用。
秦jh
2024/01/19
1250
动态内存管理
相关推荐
C语言详解(动态内存管理)1
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验