【C语言】动态内存管理:malloc、calloc、realloc、free

news2024/9/28 18:16:45

 本篇介绍一下C语言中的malloc/calloc/realloc。 使用这些函数需要包含头文件<stdlib.h>。malloc/calloc/realloc申请的空间都是 堆区的。

1.malloc和free

1.1 malloc

C语言提供了一个动态内存开辟的函数malloc,函数原型如下。

void* malloc(size_t size); //size的单位是字节

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

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

如果开辟失败,则返回NULL,因此malloc的返回值一定要做检查

返回值类型是void*,所以malloc函数并不知道开辟空间的类型,具体要在使用的时候自己来决定。要强制类型转换。

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

 比如我们申请20个字节,用来存放整形。下面两种写法是一样的。

int* p0 = (int*)malloc(20);
int* p1 = (int*)malloc(5 * sizeof(int));

然后检查一下返回值。

int* p0 = (int*)malloc(20);
//检查返回值
if (p0 == NULL) //申请失败
{
	perror("malloc fail"); 
	return 1;
}

申请成功就可以使用空间了。当作数组使用就行。

 然后我们往里面存一些值进去

1.2 free

申请的空间不要了,还要手动换回去。C语言提供了另一个函数free,专门是用来做动态内存释放和回收的,函数原型如下。

void free(void* ptr);

free函数用来释放动态开辟内存。ptr传的是要释放的内存空间的起始地址

如果参数ptr指向的空间不是动态开辟的,那么free的行为是未定义的。

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

拿前面的p0举例,我们现在要释放它。

free(p0); //把空间还给操作系统

 

此时p0指针什么都没指,是个野指针,所以我们还要手动把p0置为NULL,这一步千万不能忘。

free(p0); //把空间还给操作系统
p0 = NULL; //置空

 所以我们在使用申请的空间的时候,要记得记录起始位置指针,最好就是别改变起始位置指针的指向。

2.calloc和realloc

2.1 calloc

C语言还提供了一个函数叫做calloc,这个函数也是用来动态内存分配的,原型如下。

void* calloc(size_t num, size_t size);

 函数功能是为num个大小为size的元素开辟空间,并且把空间的每个元素初始化为0

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

比如我们想向内存申请5个整形的空间。

int* p1 = (int*)calloc(5, 4);
int* p1 = (int*)calloc(5, sizeof(int)); //这样写也可以

同样的,要检查返回值。

int* p1 = (int*)calloc(5, sizeof(int));
if (p1 == NULL)
{
	perror("calloc fail");
	return 1;
}

我们通过调试看p的内存,发现都初始化为了0。 

 除了calloc能初始化,其他的和malloc没什么区别。

最后也是一样,不用了就free,并且把p1置空。

free(p1);
p1 = NULL;

2.2 realloc

realloc的出现让动态内存管理更加灵活,它可以调整动态开辟内存的大小,函数原型如下。

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

ptr是要调整的内存地址,size是调整之后新的大小,返回值为调整之后的内存起始位置。

比如说我要把前面的p0申请的20个空间扩展到40个。有下面的两种情况。

情况一:直接在原来的基础上往后扩展就行,然后返回起始地址。 

情况二 :

        1.在内存里重新找一块区域,这块区域直接满足40个字节的需求。

        2.把原来的内容都拷贝在这个新内存里。

        3.释放旧空间。(realloc主动释放,不用自己手动释放)

        4.返回新的内存空间的起始地址。

情况三:新找的空间也不够,直接返回NULL。

所以我们在使用realloc的时候就不能直接像下面这样写。

int* p0 = (int*)malloc(20);
if (p0 == NULL) 
{
	perror("malloc fail");
	return 1;
}
for (int i = 0; i < 5; i++)
{
	*(p0 + i) = i;
}

int* p0 = (int*)realloc(p0, 40); //错误写法

因为一旦扩容失败,返回NULL,把NULL放在p0里,不但没有调整空间,原来的数据也丢失了。所以不能直接用原来的指针直接接受扩容后的新地址,要先进行一个判断,如下。

int* newptr = (int*)realloc(p0, 40);//新指针接收
if (newptr != NULL) //判断是否成功
{
	p0 = newptr; //成功了再用原来的指针接管扩容后的空间
}
else //失败
{
    perror("realloc fail"); 
	//...
}

 不用了同样要free释放。

realloc函数的第一个参数如果传NULL指针的话,可以实现和malloc一样的功能。

realloc(NULL, 20); //== malloc(20);

3.常见的动态内存错误

3.1 对NULL指针解引用

void test1()
{
	//INT_MAX是int最大值,此时空间开辟绝对是失败的
	int* p = (int*)malloc(INT_MAX); 
	*p = 20;  //开辟空间失败返回NULL,不能对NULL解引用
	free(p);
	p = NULL;
}

所以我们一定要判断malloc的返回值。 

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

void test2()
{
	int i = 0;
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		return;
	}
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = i;  //当i为10时越界访问
	}
	free(p);
	p = NULL;
}

malloc申请的空间和数组非常相似,不可以越界访问。

3.3 对非动态开辟的内存使用free释放

void test3()
{
	int a = 10;
	int* p = &a;
	free(p);
    p = NULL;
}

不是动态开辟的空间不需要free,int的空间在栈上,也不在堆上,动态申请的才在堆区上。free只释放动态开辟的。

3.4 使用free释放一块动态开辟内存的一部分

void test4()
{
	int* p = (int*)malloc(100);
	p++;
	free(p); //p此时不再指向起始位置
	p = NULL;
}

free(ptr)我们前面说过ptr必须是起始位置。只释放一部分程序会出错崩溃。

3.5 对同一块内存多次释放

void test5()
{
	int* p = malloc(100);
	free(p);
	free(p); //不可重复释放
}

这种情况最好避免发生的方法就是free之后赶紧置空。

void test5()
{
	int* p = malloc(100);
	free(p);
	p = NULL;
	free(p); //free空,什么都不发生
}

 

3.6 动态开辟的内存忘记释放

void test6()
{
	int* p = (int*)malloc(100);
	if (NULL != p)
	{
		*p = 20;
	}
}
int main()
{
	test6();
	//出test6函数后p就销毁了,想释放现在也释放不了
	
	while (1);//程序死循环

	return 0;
}

自己已经不用了,不释放不还给操作系统,别人也不能用,会发生内存泄漏问题。

但是我们不用free释放,程序运行结束的时候,也会由操作系统回收,如果程序一直不退出呢?所以最好别忘记释放。

本篇分享就到这里,拜拜~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2174365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实例讲解电动汽车故障限功限速控制策略及Simulink建模方法

电动汽车出现转向系统、制动系统及其他对车辆行车产生一定风险的故障&#xff0c;整车控制器判定为二级故障&#xff0c;功率限制为正常状态的50%&#xff0c;车速限制至20km/h。当车辆进入二级故障后&#xff0c;VCU需要根据故障处理机制进行限功限速控制。有关故障分级处理策…

基于php的在线租房管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

DIDIDI~

1 最佳速通时间 小C准备参加某个游戏的速通比赛&#xff0c;为此他对该游戏速通了 n次&#xff0c;每次速通记录可以用一个数组 A{a1,a2……am}表示&#xff0c;其中a表示小C 从游戏开始到第i个游戏节点所花赛的时间&#xff0c;m 为游戏节点的个数。请根据小 C 的速通记录计算…

IP地址如何与网络虚拟化技术融合?

网络虚拟化技术简介 网络虚拟化是一种将物理网络资源抽象为逻辑网络资源的技术。它可以将一个物理网络划分为多个虚拟网络&#xff0c;每个虚拟网络都可以有自己独立的IP地址空间、路由策略和安全设置。网络虚拟化技术为企业和组织提供了更高的灵活性、可扩展性和安全性。 IP…

DCDC电源设计工具(软件)(一)—— WEBENCH(TI)

目录 一、简介 二、在线链接 三、设计界面介绍 1、首界面 2、芯片选择或芯片选型界面 3、根据参数选择芯片及设计 &#xff08;1&#xff09;参数输入界面 &#xff08;2&#xff09;芯片选型界面 &#xff08;3&#xff09;根据具体芯片型号选择设计 ①、芯片选择及参…

BAAI 团队发布多模态模型 Emu3

在人工智能的浩瀚海洋中&#xff0c;一艘名为Emu3的创新之船正在破浪前行&#xff0c;为我们展示了多模态AI的无限可能。这个由Meta AI研究团队开发的革命性模型&#xff0c;通过简单而巧妙的"下一步预测"机制&#xff0c;实现了文本、图像和视频的统一处理。 Emu3的…

Qt/C++ 解决调用国密SM3,SM4加密解密字符串HEX,BASE64格式转换和PKCS5Padding字符串填充相关问题

项目中遇到了需要与JAVA WEB接口使用SM3,SM4加密数据对接的需求&#xff0c;于是简单了解了下SM3与SM4加密算法在C环境下的实现。并使用Qt/C还原了在线SM3国密加密工具和在线SM4国密加密解密工具网页的示例功能的实现 目录导读 前言SM3算法简介SM4算法简介 实现示例字符串HEX,B…

防伪溯源查询系统V1.0.5

多平台&#xff08;微信小程序、H5网页&#xff09;二维码扫码输码防伪溯源查询系统&#xff0c;拥有强大的防伪码生成功能&#xff08;内置多种生成规则&#xff09;、批量导出防伪码数据、支持代理商管理端&#xff08;可批量对自己防伪码进行操作处理&#xff09;、文章资讯…

SAP Message - self-explanatory 自身说明

SAP Message 解释、创建和应用可见如下文章&#xff1a;SAP Abap】SE91 - SAP MESSAGE 消息类创建与应用-CSDN博客 SE91 SAP消息类型 - tongxiaohu - 博客园 这里主要想聊一下常用的SE91 中不常用的功能 - 自身说明 选项的作用。 以 VF - 004 为例&#xff1a; 我们都知道自…

一些超好用的 GitHub 插件和技巧

聊聊我平时使用 GitHub 时学到的一些插件、技巧。 ‍ ‍ 浏览器插件 在我的另一篇博客 浏览器插件推荐 里提到过跟 GitHub 相关的一些插件&#xff0c;这里重复下&#xff1a; Sourcegraph&#xff1a;在线打开项目&#xff0c;方便阅读&#xff0c;将 GitHub 变得和 IDE …

AI名词扫盲

本篇章主要介绍一些AI研究方向的名词以及解释&#xff0c;后续会持续补充&#xff0c;名词解释与时间顺序无关&#xff0c;欢迎各位大佬们在评论区查漏补缺。 目录 AI&#xff08;Artificial Intelligence&#xff0c;人工智能&#xff09;卷积神经网络&#xff08;CNN&#xf…

权威人工智能行业认证证书——计算机视觉工程师(中级)

随着人工智能技术的快速发展&#xff0c;越来越多的人开始关注并学习人工智能。然而&#xff0c;由于人工智能领域知识的复杂性和多样性&#xff0c;许多人往往会感到困惑&#xff0c;不知道该从何入手。这时&#xff0c;一份权威的人工智能行业证书可以帮助学习者更好地了解人…

SpringBoot3.X配置OAuth

背景 之前在学习OAuth2时&#xff0c;我就有一个疑惑&#xff0c;OAuth2中有太多的配置、服务类都标注了Deprecated&#xff0c;如下&#xff1a; 显然这些写法已经过时了&#xff0c;那么官方推荐的最新写法是什么样的呢&#xff1f;当时我没有深究这些&#xff0c;我以为我放…

Gartner 报告解读(二)| Open Telemetry可观测性解读与使用建议

上期跟大家解读了Gartner 成熟度曲线报告&#xff0c;主要分享了影响中国IT使用的4大因素--自主可控计划、AI发展趋势影响、降本增效、IT基础设施现代化程度。新来的朋友点这里&#xff0c;一键了解具体内容。 Gartner 成熟度曲线报告解读&#xff08;一&#xff09;| 2024中国…

sentinel原理源码分析系列(二)-动态规则和transport

本文是sentinel原理源码分析系列第二篇&#xff0c;分析两个组件&#xff0c;动态配置和transport 动态规则 Sentinel提供动态规则机制&#xff0c;依赖配置中心&#xff0c;如nacos&#xff0c;zookeeper&#xff0c;组件支持动态配置&#xff0c;模板类型为规则&#xff0c;支…

字节跳动青训营x豆包Marscode 技术训练营报名啦!

最近字节跳动青训营又开营了&#xff0c;作为第二次参加的我来给没有了解过的同学从几个方面简单介绍一下。 青训营是什么 青训营是字节跳动 稀土掘金 社区发起的技术系列培训 & 人才选拔项目&#xff0c;面向在校大学生&#xff0c; 课程全程免费&#xff0c;包含前端、…

mov视频怎么转换成mp4?这几种转换方法值得收藏起来!

mov视频怎么转换成mp4&#xff1f;MOV格式&#xff0c;作为苹果专属的产物&#xff0c;它在非苹果体系下的兼容性常常受限&#xff0c;导致用户可能在非苹果软件平台上遭遇播放难题&#xff0c;甚至无法顺利加载视频内容&#xff0c;而且&#xff0c;MOV格式以其独特的压缩技术…

sentinel原理源码分析系列(三)-启动和初始化

本文是sentinel原理源码分析系列第三篇&#xff0c;分析sentinel启动和初始化 启动/初始化 sentinel初始化分两块&#xff0c;静态初始和适配器(包括aop) 静态初始 1. Root EntranceNode 如果我们用一栋楼类比资源调用&#xff0c;root EntranceNode好比一栋楼的大门&…

干货 | 2024制造业数字化现状调查白皮书(免费下载)

导读&#xff1a;在这本白皮书中&#xff0c;我们询问了制造商有关数字化转型的工作情况、2024 年的优先事项和可持续性。研究结果清楚地表明&#xff0c;在数字化方面处于领先地位的制造商转型项目比那些没有规划或刚刚起步的项目实现的价值要大得多。 加入知识星球或关注下方…

windows11下vscode配置lua环境

一、lua插件的安装&#xff1a; 建议安装sumneko下的lua插件&#xff1a; 安装luadebug&#xff1a; 二、运行lua配置 安装code runner插件&#xff1a; 配置code runner 配置lua运行环境&#xff1a; 运行code&#xff0c;直接run code即可&#xff1a;