内存分配函数(动态内存分配)详解

news2024/12/24 9:31:17

目录

    🎑为什么要进行动态内存开辟?

    🎑malloc和free

    🎠malloc函数

    🎠free函数

    🎠malloc函数和free函数的实际应用

    🎑calloc函数

    🎑realloc函数

    🎠realloc函数的使用示例

    🎏大家好,本次博客的主要内容是与内存分配相关的函数详解。在学习这部分内容之前我们先来普及一个小知识,以便于我们更好地理解为什么要采用动态内存分配。

    🎏首先我想要告诉大家的是,在我们的计算机上不同的数据存储的位置不同。存储数据的区域大致分为三个部分:

               🎐第一部分    栈区:主要存储局部变量和函数形参。

    🎏由于我们的局部变量大多具有特定的生命周期属于临时存储,一旦出了变量的作用域就会被销毁,(主函数除外,在主函数中创建的局部变量到程序结束的时候才会被销毁。)具有很高的再利用的特点,所以栈区在内存中所占的空间不大。

               🎐第一部分    堆区:主要进行动态内存开辟。(是我们本次主要讲的对象。)

               🎐第一部分    静态区(也叫数据段):主要用于存储全局变量以及静态变量。

    🎏存储在静态区中的数据只有当程序结束的时候才会被销毁。

    🎏有了上面的铺垫那么我们就可以开始我们今天内存分配函数相关知识的讲解了。

    🎑为什么要进行动态内存开辟?

    🎏动态内存开辟也就是在堆区上面开辟一块空间供我们利用,但是很多小伙伴在刚开始的时候并不明白为什么要在堆区里开辟一块空间,明明我们直接创建临时变量的时候就可以直接进行使用了呀?

    🎏还记得我们上面提到的局部变量的存储位置是在栈区上吗?因为栈区中的内容可以反复利用(出作用域局部变量就被销毁)所以我们栈区的大小并不大。但是在主函数中创建的临时变量的生命周期又是整个程序的运作周期,那么假设我们想要在主函数中创建一个很大的数组,是否有可能将我们栈区的内容完全占据呢?没错,在堆区上进行动态内存开辟就是为了避免这种情况的发生。是不是理解了不少呢?我们接下来就进入动态内存分配相关知识的正式讲解。

    🎑malloc和free

    🎏对于一个未知的函数我们第一步要做的就是先了解这个函数参数以及返回类型是什么,因此我们先通过两张张图片初步认识一下malloc函数和free函数的参数与返回类型,之后再对这两个函数进行进一步的解说。

    🎠malloc函数

     🎏我们通过上面的图片可以看到 malloc 函数的参数为一个无符号整数,返回类型为 void * 类型。其中作为参数的无符号整数是我们想要在堆区中开辟的字节的个数。因为 malloc 函数的返回类型是一个指针类型所以我们接收 malloc 函数的返回值的时候需要用一个指针变量进行接收。

    🎏 malloc 函数会向堆区申请开辟一块连续可用的空间。 如果开辟成功,则返回一个指向开辟好空间的指针(该空间的首地址,可以类比于数组的首地址)。 如果开辟失败,则返回一个NULL指针(堆区中已经没有符合条件的连续的空间以供开辟使用)。因此malloc的返回值一定要做检查。

    🎏返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。但是需要我们注意的是:对于 void * 类型的指针我们在使用的时候不能直接进行解引用得到我们想要的值,因此我们在接收 malloc 函数的返回值的时候需要进行强转操作,将 void * 转换成我们需要的相关类型的指针,以便我们更好的使用。

    🎠free函数

     🎏相比较于 malloc 函数来说我们的 free 函数就简单得多,但是其重要程度并不亚于任何动态内存开辟函数。经过上图我们可以知道的是 free 函数的参数为一个任意类型指针(实际上就是我们在上一步骤用来接收开辟动态内存的指针。)无返回类型因此我们并不需要注意。

    🎏free函数是专门是用来做动态内存的释放和回收的,当我们在堆区中开辟一块空间之后系统并不会在我们使用完主动将这块区域释放还给操作系统,动态开辟出来的内存只能手动free释放或者在程序结束时自动释放。所以假如我们的程序时一个全日制的程序,24小时均进行工作,在使用完开辟好空间之后不主动进行释放的话就有可能造成内存泄露的风险。(所谓的内存泄漏也就是指堆区中的内存遗失,无法再次被找到,最终导致内存被占满,进而死机)如:

    🎏需要特别指出的是在使用所有动态内存分配函数的时候均需要引入一个头文件<stdlib.h>!!!经过我们上面的介绍,相信大家对 malloc 函数和 free 函数已经有了大致的印象,为了让大家彻底领悟到 malloc 函数和 free 函数的使用方法,我们接下来开一个例子。

    🎠malloc函数和free函数的实际应用

    🎏我们先来观察下面一段代码进而感受以下 malloc 和 free 函数的使用方法:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	//向堆区中申请一块大小为40个字节的空间
	int* p = (int*)malloc(10 * sizeof(int));
	//对malloc函数的返回值进行判空处理
	if (p == NULL)
	{
		perror("main:");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p+i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p+i));
	}
	//释放使用后的空间
	free(p);
	p = NULL;
	return 0;
}

    🎏我么可以观察上面的代码,会发现有许多细节的地方。

            🎐 NUM 1:我们在用整形指针 p 接收 malloc 返回的指针的时候下一步操作会对 p 指针进行判空处理,这是因为,malloc 函数在开辟内存失败的时候会返回一个空指针即 NULL ,如果我们不对 p 进行判空处理的话就存在直接使用空指针的可能。而对空指针进行解引用会使我们的程序异常,导致程序崩溃。如:

             🎐 NUM 2:在我们的使用达到目的时(打印出 0-9 数字之后)立即释放动态开辟的内存,防止因为以往造成内存泄漏(养成良好的习惯)。

             🎐 NUM 3:在释放完内存之后将用于接收 malloc 返回值的指针手动置成空指针。防止野指针的出现,造成异常访问。

    🎏上面就是我们的 malloc 函数和 free 函数的主要使用,接下来我们来接着认识一下 calloc 函数。

    🎑calloc函数

    🎏 calloc 函数其实与我们的 malloc 函数很相似,只不过参数等方面有些变化。同样的我们先从calloc 的函数原型进行认识该函数。

    🎏我们可以看到 calloc 函数返回类型和 malloc 函数相同都为一个指针,这个指针也同样符合malloc 函数的返回原则,即成功开辟空间返回首地址,开辟失败返回 NULL 。但是我们会发现 calloc 函数在参数上和 malloc 有些许差异。

    🎏实质上 calloc 函数的功能是在堆区上开辟一块元素个数为 num 个,元素所占空间大小为 size 字节的空间。(我们可以将其认为时 malloc 函数参数的分解)如:我们需要开辟十个整形,用 malloc 函数表达的形式是 malloc(40),而用 calloc表达就是 calloc(10,4)。

    🎏还有一点 calloc 与 malloc 函数具有明显的区别,那就是 malloc 虽然可以进行空间上的开辟,但是不能对空间上各元素进行初始化,而我们的 calloc 函数为我们开辟了一段连续的空间之后还会自动将我们的数据初始化为0。

    🎏我们可以通过一段代码来体现 calloc 与 malloc 函数的相同之处与不同之处:

// malloc函数
//#include<stdio.h>
//#include<stdlib.h>
//int main()
//{
//	int* p = (int*)malloc(10 * sizeof(int));
//	if (p == NULL)
//	{
//		perror("main");
//		return 1;
//	}
//	int i = 0;
//	for (i = 0; i < 10; i++)
//	{
//		printf("%d\n", *(p + i));
//	}
//	free(p);
//	p = NULL;
//	return 0;
//}

//calloc函数
#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
		perror("main");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", *(p + i));
	}
	free(p);
	p = NULL;
	return 0;
}

    🎏我们通过上面的运行截图也可以发现两者之间的区别。其余方面两函数均相同。再次声明请注意以下几点:

           🎐 NUM 1:对接收返回值的指针进行判空操作!!

           🎐 NUM 2:使用完函数时对动态开辟的空间进行释放!!

    🎏毕竟重点说几遍都不算多,那么我们来继续来介绍我们最后一个内存开辟函数——realloc。 

    🎑realloc函数

    🎏realloc函数的出现让动态内存管理更加灵活。 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时 候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。老规矩我们先从函数原型进行了解。

    🎏 我们首先来认识一下这个函数的参数和返回值(和我们之前认识到的 malloc 和 calloc 函数区别可不小哦):

                     🎐ptr 是要调整的内存地址

                     🎐size 调整之后新大小

                     🎐返回值为调整之后的内存起始位置。

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

                               🎊情况1:原有空间之后有足够大的空间,要扩展内存就直接原有内存之后直                                                   接追加空间,原来空间的数据不发生变化。

                               🎊情况2:原有空间之后没有足够大的空间,原有空间之后没有足够多的空间                                                   时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来                                                      使用。这样函数返回的是一个新的内存地址,之前开辟的空间自动                                                  被系统释放。

                               🎊情况3:找不到合适的内存进行开辟返回空指针即 NULL 。

                      🎐假如为第二种情况,realloc 函数还会将原来内存中的数据移动到新的空间。

                      🎐特别指出一点:为了防止 relloc 函数返回空指针导致原先指针位置丢失,所以应                                                       当先使用新建的指针进行接受进行判空处理之后,再赋给 p 。

    🎏我们通过一张图进行理解这三种情况。

    🎏同样的我们先了解了 relloc 函数的大致用法接着通过具体的例子进一步了解该函数的使用方法。

    🎠realloc函数的使用示例

#include<stdio.h>
#include<stdlib.h>
int main()
{
	//在堆区上开辟40个字节大小
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//将上面开辟的内存大小拓展成80个字节
	int* pstr = (int*)realloc(p, 20 * sizeof(int));
	if (pstr == NULL)
	{
		perror("realloc");
		return 2;
	}
	p = pstr;
	for (i = 10; i < 20; i++)
	{
		*(p + i) = i;
	}
	for (i = 0; i < 20; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p);
	p = NULL;
	return 0;
}

     🎏我们可以通过上面的代码知道,当我们第一次开辟的内存假如不够用的时候可以用 realloc 函数重新调整内存块的大小(上面代码中由40个字节调整至80个字节)。同样的我们也可以通过监视窗口观察我们上面所说的三种情况。

                 🎐第一种情况存在足够的空间直接在后面扩展。返回指针不改变。

                 🎐第二种情况 p 后并不直接存在可用空间寻找并开辟新的空间,返回新的指针。

                 🎐第三种情况找不到合适的空间,返回空指针。

    🎏经过我们上面的验证,相信大家已经对 realloc 函数已经基本上了解了。那么我们再来举一个特殊一点的例子:malloc 和 realloc 的等价互换。

    🎏当 ralloc 函数中的指针参数为 NULL 时,其作用等价于 malloc 即 realloc(NULL,40)等价于 malloc(40)。都是在堆区中开辟一个大小为40个字节的空间以供我们使用。

    🎏那么以上就是我们本次博客的全部内容了,感谢大家的观看,祝大家天天开心。

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

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

相关文章

通过脚手架vue-cli创建一个vue项目

我需要在vue-demo文件下新建vue项目 步骤一 ①在该文件夹下打开集成终端 输入创建命令 命令 vue create 项目名称 &#xff0c;注意不要使用驼峰命名法 如果是第一次配置&#xff0c;有面的提示&#xff0c;这里说你这样速度会很慢的&#xff0c;用不用镜像啊&#xff0c;这…

样品制备丨艾美捷硝酸盐/亚硝酸盐荧光法检测试剂盒

一氧化氮&#xff08;NO&#xff09;是由一氧化氮合酶&#xff08;NOS&#xff09;在生物系统中合成的。NOS是一种非常复杂的酶&#xff0c;作用于分子氧、精氨酸和NADPH&#xff0c;产生NO、瓜氨酸和NADP。这个过程需要五个额外的辅因子&#xff08;FMN、FAD、血红素、钙调素和…

制造业ERP管理系统在企业采购管理中的作用是什么?

对于任何一家企业&#xff0c;采购都是头等大事。企业的采购工作往往是决定了企业产品的交货速度、成本和质量&#xff0c;特别是在制造行业&#xff0c;采购成本甚至占比产品成本的60%以上&#xff0c;降低采购成本是提高企业竞争力的关键。因此&#xff0c;对于企业采购领域的…

Effective C++条款34:区分接口继承和实现继承

Effective C条款34&#xff1a;区分接口继承和实现继承&#xff08;Differentiate between inheritance of interface and inheritance of implementation&#xff09;条款34&#xff1a;区分接口继承和实现继承1、纯虚函数2、虚函数&#xff08;非纯&#xff09;2.1 将默认实现…

2022 IoTDB Summit:中国核电刘旭嘉《工业时序数据库 Apache IoTDB 在核电的应用实践》...

12 月 3 日、4日&#xff0c;2022 Apache IoTDB 物联网生态大会在线上圆满落幕。大会上发布 Apache IoTDB 的分布式 1.0 版本&#xff0c;并分享 Apache IoTDB 实现的数据管理技术与物联网场景实践案例&#xff0c;深入探讨了 Apache IoTDB 与物联网企业如何共建活跃生态&#…

middlebury立体匹配评估使用方法总结(三)——线上版教程

系列文章目录 middlebury立体匹配评估使用方法总结&#xff08;一&#xff09;——网站说明 middlebury立体匹配评估使用方法总结&#xff08;二&#xff09;——python版离线教程 middlebury立体匹配评估使用方法总结&#xff08;三&#xff09;——线上版教程 文章目录系列文…

TableLayout布局

表格布局-TableLayout 1.TableLayout简介 1.简介 表格的形式&#xff0c;整齐可以嵌套继承于线性布局2.行数如何确定&#xff1f; tableRow&#xff0c;来指定行数列数由最多的那个决定layout_column来指定具体的列数&#xff0c;从0开始2.TableLayout的常见属性 所有的都是从0…

VMware ESxi 服务器迁移【手动版】

VMware ESxi 迁移【手动版】 应用场景 两个不同环境下的服务器进行迁移 因为不能直接对拷&#xff0c;需要在中间机上转一下 才有了这么一出 第一步 搭建NFS 在中间机上安装NFS&#xff08;或者其他磁盘挂载方式&#xff09; 目的呢是把源服务器上的系统拷贝到中间机上&#x…

android入门之broadcast

1. 前言 广播Broadcast是android四大组件之一。是用来互相通信&#xff08;传递信息&#xff09;的一种机制。 通信包括&#xff1a; a) 组件间&#xff08;应用内&#xff09;通信 b) 进程间通信 2. 广播Brocast的基本使用方式 广播发送者&#xff1a;Acvitity、Service等…

pdf文档页码怎么添加?分享这几个pdf加页码方法给你

不管是还在校园里的学生&#xff0c;还是已经步入职场的小伙伴&#xff0c;都会遇到要对一些文档进行编辑处理&#xff0c;例如有时需要将word、excel、ppt等格式的文档与pdf文件进行相互转换&#xff0c;有时又需要对pdf文件进行编辑文档增加页眉页脚、拆分合并、加密解密等操…

基于Python+Echarts+Pandas 搭建一套图书分析大屏展示系统(附源码)

今天给大家分享的是基于 Flask、Echarts、Pandas 等实现的图书分析大屏展示系统。 项目亮点 采用 pandas、numpy 进行数据分析 基于 snownlp、jieba 进行情感分析 后端接口选用 RESTful 风格&#xff0c;构建 Swagger 文档 基于 Flask、Echarts 构建 Web 服务&#xff0c;采…

2022年债券估值工具和方法

第一章 债券估值原理概述 债券估值是决定债券公平价格[1]的过程。债券公平价格是债券的预期现金流经过合适的折现率折现以后的现值&#xff0c;其原理是未来现金流流出折现到今日与今日现金流流出相等。因此&#xff0c;债券的估值模型可以表示为&#xff1a; 资料来源&#x…

新冠阳性的第四篇博客,SpringBoot 任务(异步、定时、邮件)

新冠阳性的第四篇博客&#xff0c;SpringBoot 任务&#xff08;异步、定时、邮件&#xff09;1.异步任务2.邮件任务3.定时任务1.异步任务 异步处理还是非常常用的&#xff0c;比如我们在网站上发送邮件&#xff0c;后台会去发送邮件&#xff0c;此时前台会造成响应不动&#x…

Python多元线性回归、机器学习、深度学习在近红外光谱分析中的应用

导师&#xff1a;郁磊副教授&#xff0c;主要从事MATLAB 编程、机器学习与数据挖掘、数据可视化和软件开发、人工智能近红外光谱分析、生物医学系统建模与仿真&#xff0c;具有丰富的实战应用经验&#xff0c;主编《MATLAB智能算法30个案例分析》、《MATLAB神经网络43个案例分析…

【Vue】二、 认识Vue.js的各种指令

后端程序员的vue学习之路1、创建第一个vue对象2、vue构造器3、Vue.js模板语法v-text至v-for练习v-on指令练习v-bind指令练习v-model指定练习v-pre指令v-slot指令v-cloak指令v-once指令1、创建第一个vue对象 引入了vue.js后&#xff0c;在页面就可以创建一个Vue对象&#xff0c…

JS圣诞树

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。&#x1f34e;个人主页&#xff1a;Java Fans的博客&#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。&#x1f49e;当前专栏&#xff1a;前端案例分享…

this指向问题,apply,call,bind用法及区别

1.谁调用我&#xff0c;我就指向谁。 在页面上直接打印一个consle.log&#xff08;this&#xff09;,这个this会指向window对象。如果写一个函数&#xff1a;打印this,该this会指向window。因为这个函数是挂载在这个window对象上的。对象obj的this指向的是对象&#xff0c;因为…

[ 漏洞挖掘基础篇五 ] 漏洞挖掘之 XSS 注入挖掘

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

创新指南|2023年企业战略制定应避免的5大误区

在迅速发展、不断变化的当下&#xff0c;尤其是疫情黑天鹅发生之后&#xff0c;许多企业面临着高度的不确定性&#xff0c;从而亟需进行企业战略的思考。在本文中&#xff0c;战略专家Stephen Bungay指出了五个战略误区&#xff0c;并解释了它们为什么听起来正确&#xff0c;以…

基于JAVA技术的《物联网技术》课程学习网站设计与实现

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 基于JAVA技术的《物联网技术》课程学习网站设计与实现 网站前台&#xff1a;关于我们、联系我们、公告信息、资料信息&a…