C语言——动态内存管理

server/2024/10/18 14:26:06/

大家好,本期和大家分享C语言动态内存管理有关知识,记得三连支持一下哦!

2f36ea34de3940548aab5862d5eb1b2c.jpeg

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

我们目前已经知道的内存开辟方式有两种,分别是:定义变量和开辟数组空间。

这两种方式都有共同的特点:

1.内存空间都是在栈空间上开辟的;

2.开辟的空间大小是固定的,数组在声明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整。

但是我们在编程时对于空间的需求往往是在程序运⾏的时候才能知道,那么开辟的空间一开始就固定的话,这对我们编程是有很多局限性的,所以,在C语言中程序员可以动态的申请空间和释放空间,这就大大的增加了程序的灵活性。

二、malloc、calloc、realloc和free

我们要想动态的开辟空间和释放空间,就必须用到以下几个函数:

malloc、calloc、realloc和free

下面我们就依次来介绍。

1.malloc 

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

它有以下特点:

1.如果开辟成功,则返回⼀个指向开辟好空间的指针;
2.如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查;
3.返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者⾃⼰来决定;
4.如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器;

5.使用要包含头文件#include<stdlib.h>.

b25c0f8bd6504de88a89e4e4364cf867.png

如何使用呢?我们来看例子:c15ca426be6d4e5d88350cee86619f04.png

上面这段代码是以后我们经常会用到的申请空间的方式,肯定有许多小伙伴们不太理解,下面我就来讲解一下:6adc8d48ff8649049f8ea5186e01a8ec.png

在使用malloc函数是我们要注意:

1.包含头文件#include<stdlib.h>;

2.强制转换指针类型;

3.判断空间是否成功开辟;

4.使用完后要手动释放并将使用的指针置空。

2.calloc

和malloc一样,calloc也是一个开辟空间的库函数,唯一不同的是,calloc在返回地址前会把开辟的空间每个字节都初始化为0。

18c38453b2e54b60803248bc6de6a7b0.png

下面我们来看个例子:b84a64f6f5844b3492ce662eb1318220.png

calloc的使用注意事项和malloc一样,这里不再赘述。

3.realloc

realloc也是一个开辟空间的库函数,功能和malloc相似,但是又有不同之处。有时我们在开辟空间的时候也不知道具体需要多大的的空间,开大了还不要紧,但是开小了就比较麻烦了,这个时候我们就可以使用realloc来解决这个问题。realloc 函数就可以做到对动态开辟内存⼤⼩的调整。

ce6e0646148b4724ba493ba721464915.png

1.ptr是要调整的内存地址;
2.size 调整之后新⼤小;
3.返回值为调整之后的内存起始位置;
4.这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动到新的空间。

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

(1)原有空间之后有⾜够⼤的空间:
要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化;

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

下面我们画图来理解一下:

a67822de9d054f858fbb9cb9ad245547.png

在这里我们还要注意的是:情况(2)中新空间开辟之后会把原有空间中的数据拷贝到新空间中。

所以说realloc函数的功能还是很强大的。功能强大那么我们使用时需要注意的地方就更多,下面我们就来看看例子:

539146e2b0ba430b9d563dbc7281b029.png

我们看这段代码好像没有什么问题,但它存在着一定的缺陷:

我们思考一下如果realloc扩容失败会怎么样?

上面说过realloc扩容失败会返回空指针,这就会导致前面的数据全都丢失了,这就非常得不偿失了。所以我们应该这样优化:

0fd3d8d9559046f49be54de4d8602216.png

这样优化就能防止上面的情况出现。

当然,在通常情况下,realloc是可以当成malloc使用的

4.free

free是一个释放空间的库函数,在上面我们也使用过了,下面我们具体来介绍一下。

d879899766f24600a970869314414850.png

free函数⽤来释放动态开辟的内存。
如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。

注意:malloc、calloc、realloc主动申请的空间都需要我们手动释放,如果不主动释放,除了作用域不会自动销毁就可能导致内存泄漏。

三、常⻅的动态内存的错误

下面我们来看一些动态内存常见的错误

1.对NULL指针的解引⽤操作

115f83bf37c647c0ad8ee7e9bb399b56.pngf2271fc9758343b288aa00b86a0a0d81.png

我们可以看到上面两段代码都警告说取消对空指针的引用,第一段代码当然运行时会崩掉,第二段代码即使运行出来了也只是没有遇到极端情况,遇到极端情况也是会崩的。

eb59d1ef56c3499eb6ecfbe5b5ec2d93.png

所以我们通常在使用开辟空间这些函数后要检查一下是否开辟成功,防止传回空指针导致下面的程序出错。

我们在使用指针时也要注意不要对空指针解引用。

2.对动态开辟空间的越界访问

对动态开辟空间的越界访问和数组越界访问相似,都是访问到不属于你的空间,这个时候往往会导致报错。

8db793fadf1846ef8e85bfc975ca11c9.png

我们看到在VS上没有报错,这是因为VS环境还是比较友好的,但也报了警告,在其他环境下就不一定了。所以无论是数组还是动态开辟的空间我们都要控制好数据,防止越界访问。

3.对⾮动态开辟内存使⽤free释放

我们知道我们定义的变量系统会自己分配空间,当出了作用域时系统会自己销毁,不需要我们自己手动销毁。如果我们去干别人的事,就会出现问题。如:

e2f5ee40457640c48f9c165a88c99ecd.png

4.使⽤free释放⼀块动态开辟内存的⼀部分

我们在做一件事的时候要去做完才算成功,free释放空间也是这样的。只释放一部分也会出现问题,如:

f6f94e4240ba4d19a5500ac944ae716e.png

5.对同⼀块动态内存多次释放

当然一块空间释放完了,我们就不需要再去释放一遍,否则就会出现错误。

0e1c08af2c334825a77f98ce28f2a21d.png

6.动态开辟内存忘记释放

这个问题我们上面也多次强调过,动态开辟的内存一定要手动释放掉,否则会导致内存泄漏。

一次我们可能察觉不到,但是在一个项目里,我们每次动态开辟的空间都不释放,到后面累计的到一定程度将会成为一个大问题。

所以:切记,动态开辟的空间⼀定要释放,并且正确释放。

四、C语言中程序内存区域划分

在上面我们提到栈、堆等等到底是什么呢?其实它们是内存中的区域划分。下面就来具体介绍一下C语言中内存区域是如何划分的。

8bf86cd6991b466db1f3d4ed554b2245.png

1. 栈区(stack):在执⾏函数时,函数内局部变量的存储单元都可以在栈上创建,函数执⾏结束时这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中,效率很⾼,但是分配的内存容量有限。栈区主要存放运⾏函数⽽分配的局部变量、函数参数、返回数据、返回地址等;
2. 堆区(heap):⼀般由程序员分配释放,若程序员不释放,程序结束时可能由系统回收。分配⽅式类似于链表;
3. 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放;
4. 代码段:存放函数体(类成员函数和全局函数)的⼆进制代码。

好了,以上就是本篇文章的全部内容了,创作不易,记得三连支持一下哦!我们下期再见!

812dd1a160274e53b45d2b148cd7ba71.gif


http://www.ppmy.cn/server/24594.html

相关文章

OpenAI 新推出 AI 问答搜索引擎——SearchGPT 震撼登场

您的浏览器不支持 video 标签。 OpenAI-SearchGPT 近日&#xff0c;OpenAI 曝光了自己的一款令人瞩目的 AI 问答搜索引擎——SearchGPT。这款搜索引擎带来了全新的搜索体验&#xff0c;给整个行业带来了巨大的压力。 SearchGPT 支持多种强大的功能。首先&#xff0c;它能够通过…

Spark 为什么比 Hive 快

文章目录 数据处理方式不同并行方式不同稳定性不同Shuffle 方式不同 数据处理方式不同 Spark 是基于内存计算的分布式计算框架&#xff0c;可以在内存中高效地执行数据操作&#xff0c;因此通常比 Hive 更快。Spark 会尽可能将数据加载到内存中&#xff0c;并在内存中执行多个…

python自动化生成ppt

使用Python和python-pptx创建PPT 在这篇博客中&#xff0c;我们将探讨如何使用Python库python-pptx来创建一个简单的PowerPoint演示文稿&#xff08;PPT&#xff09;。这个库允许我们以编程方式创建幻灯片、添加文本、图片、表格和自定义形状。 安装python-pptx 首先&#x…

look-behind requires fixed-width pattern_正则表达式

问题&#xff1a;例如我想要匹配一段文本中&#xff0c;字符“a”在“小猫”的前面&#xff0c;中间有可能间隔好几个字符&#xff0c;也有可能直接相邻。结果只返回“小猫”。 import re text "这是一只非常可爱的a的的小猫." pattern r"(?<a*)小猫"…

[C++][算法基础]最大不相交区间数量(贪心 + 区间问题2)

给定 &#x1d441; 个闭区间 [&#x1d44e;&#x1d456;,&#x1d44f;&#x1d456;]&#xff0c;请你在数轴上选择若干区间&#xff0c;使得选中的区间之间互不相交&#xff08;包括端点&#xff09;。 输出可选取区间的最大数量。 输入格式 第一行包含整数 &#x1d4…

JavaEE技术之MySql高级(索引、索引优化、sql实战、View视图、Mysql日志和锁、多版本并发控制)

文章目录 1. MySQL简介2. MySQL安装2.1 MySQL8新特性2.2 安装MySQL2.2.1 在docker中创建并启动MySQL容器&#xff1a;2.2.2 修改mysql密码2.2.3 重启mysql容器2.2.4 常见问题解决 2.3 字符集问题2.4 远程访问MySQL(用户与权限管理)2.4.0 远程连接问题1、防火墙2、账号不支持远程…

使用selenium时出现element click intercepted报错的解决办法

win10&#xff0c;python3.8.10。 selenium版本如下&#xff08;用pip38 show selenium查看&#xff09;&#xff1a; 在定位中&#xff0c;定位了一个按钮&#xff08;特点&#xff1a;button下还有span然后才是文本&#xff09;&#xff0c;代码如下&#xff1a; from sele…

梯度提升回归(概念+实例)

目录 前言 一、基本概念 1. 弱学习器&#xff08;Weak Learners&#xff09; 2. 提升&#xff08;Boosting&#xff09; 3. 梯度提升算法&#xff08;Gradient Boosting Algorithm&#xff09; 3.1. 梯度下降 3.2. 回归问题中的梯度提升 4. 梯度提升回归的训练过程 5.…