【C语言】内存操作篇---动态内存管理----malloc,realloc,calloc和free的用法【图文详解】

欢迎来CILMY23的博客喔,本篇为【C语言】内存操作篇---动态内存管理----malloc,realloc,calloc和free的用法【图文详解】,感谢观看,支持的可以给个一键三连,点赞关注+收藏。

前言

 在学完结构体后(结构体1:http://t.csdnimg.cn/ZkBHj结构体2:http://t.csdnimg.cn/rmAwJ)我们要进入新篇章了,内存操作中最关键的一节---动态内存管理,本篇博客将了解malloc,realloc,calloc和free的用法。

目录

一、为什么会有动态内存管理?

二、malloc和free

malloc的介绍和使用  

空间回收 

free的介绍和使用

三、realloc

realloc的介绍和使用 

四、calloc 

calloc的介绍和使用 


一、为什么会有动态内存管理?

 在过去我们向内存中申请空间有两种方式,一是创建变量,二是创建数组

#include<stdio.h>

int main()
{
	int C = 23;//申请四个字节空间
	char c = 'C';//申请1个字节空间
	char CI[10] = "CILMY23";//申请10个字节空间
	return 0;
}

但是上述的开辟空间的方式有两个特点:
•    空间开辟大小是固定的。
•    数组在声明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整
我们申请的空间都很固定,没法灵活调整,但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组和变量的编译时开辟空间的方式就不能满足了。
C语言引入了动态内存开辟,让程序员自己可以申请和释放空间,就比较灵活了。 

二、malloc和free

malloc可以在cplusplus网站查询:malloc - C++ Reference (cplusplus.com)  

 malloc函数原型如下:

void* malloc (size_t size);

 malloc的函数介绍如下:

malloc 的功能如下:

malloc的介绍和使用  

malloc函数是头文件stdlib中的,malloc函数是用来向内存申请空间的(在堆区申请),在函数原型中我们可以看到有一个形参size_t size,根据Allocates a block of size bytes of memory, returning a pointer to the beginning of the block,我们知道这个形参是计算空间大小后得出的结果,比如申请40个字节空间,size就等于40.那它最后会返回一个指针,指向这个空间的起始位置,那返回类型是void*,因为我并不知道这段空间会干什么,所以返回void*(不懂可以看http://t.csdnimg.cn/dshm8),当malloc失败后,会返回一个NULL。

使用如下:

#include<stdio.h>
#include<stdlib.h>

int main()
{
	// 向内存空间申请40个字节
	//将void*转换成int*类型将其存入指针变量p
	int* p = (int *)malloc(10 * sizeof(int));

	int i = 0;
	//将i存入开辟的空间
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//将空间中的数值打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
}

结果如下:

 

 图解如下:

 那如果我们申请失败了呢?那我们就可以用perror来直接打印错误信息。

if (*p == NULL)
{
	perror("malloc");
}

空间回收 

malloc是在堆区申请空间的,malloc的空间回收有两种方法,一是free回收,二是程序结束的时候,由操作系统回收 我们这里主要讲free回收,首先回顾一下内存的区域,主要由堆区栈区和静态区构成,堆区是动态分配区,像malloc这些,栈区是临时的参数,局部变量和形式参数,静态区主要是全局变量和静态变量。

 
     

free的介绍和使用

free函数的原型如下:

void free (void* ptr);

free函数介绍如下:

 free的功能和使用案例如下:

free函数是用来释放动态开辟出来的空间,给到地址就能释放地址所指向的位置 

free的使用:

#include<stdio.h>
#include<stdlib.h>

int main()
{
	// 向内存空间申请40个字节
	//将void*转换成int*类型将其存入指针变量p
	int* p = (int *)malloc(10 * sizeof(int));

	if (*p == NULL)
	{
		perror("malloc");
	}
	int i = 0;
	//将i存入开辟的空间
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//将空间中的数值打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}

	free(p);
	p = NULL;
}

我们使用free(),因为我们将p所指向的空间释放了,那p就成了野指针,我们就需要处理野指针,所以将p置空。 

总结:

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

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

三、realloc

 

 realloc函数可以在cplusplus网站查询:realloc - C++ Reference (cplusplus.com)

realloc的原型如下:

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

realloc的函数介绍如下:  

realloc的功能和使用案例如下: 

realloc的介绍和使用 

 realloc的参数有void* ptr, size_t size,size就是要调整后的空间大小,ptr则是要调整的空间起始地址。realloc 的调整分两种情况,一种是原地扩,也就是后面的空间足够,如下图所示,未分配的空间加已分配的橙色空间刚好够size,或者小于size,则realloc原地扩

第二种情况是未分配的黑色空间加已分配的橙色空间,超过size后的字节,那realloc会到新的一块未分配区域重新开辟一块空间,来分配原先的字节,并将原来的地址做拷贝,最后返回新的空间地址,并且旧空间会自动释放掉。

realloc的使用:

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int* p = (int*)malloc(10 * sizeof(int));

	int i = 0;

	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}

	//调整申请的堆上内存
	int* tmp = (int*)realloc(p, 40);
	if (tmp != NULL)
	{
		p = tmp;
		tmp = NULL;
	}
	else
	{
		perror("realloc");
	}

	free(p);
	p = NULL;

	return 0;
}

总结:

• ptr 是要调整的内存地址
• size 调整之后新大小
• 返回值为调整之后的内存起始位置。
• 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
•    realloc在调整内存空间的是存在两种情况:
◦ 情况1:原有空间之后有足够大的空间
◦ 情况2:原有空间之后没有足够大的空间

四、calloc 

calloc函数可以在cplusplus网站查询:calloc - C++ Reference (cplusplus.com) 

calloc的原型如下:

void* calloc (size_t num, size_t size);

calloc的函数介绍如下: 

 

calloc的功能和使用案例如下: 

 

calloc的介绍和使用 

calloc的参数是两个,一个是num,一个是大小size,其中一个给数量,一个给大小。calloc和malloc函数最大区别就是,calloc会赋一个初值,每个初值都是0. 使用和malloc是差不多的

 

使用如下:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10 ,sizeof(int) );

	int i = 0;

	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	printf("\n");
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}

	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}

	free(p);
	p = NULL;
}

 结果如下:

 

 如果我们只是想开辟空间,我们只需要用malloc,而calloc是把开辟出来的空间赋了一个初值。

总结:

•  函数的功能是为num 个大小为size的元素开辟⼀块空间,并且把空间的每个字节初始化为0
•  与函数malloc 的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全 0

感谢各位同伴的支持,本期动态内存管理篇就讲解到这啦,如果你觉得写的不错的话,可以给个一键三连,点赞关注+收藏,若有不足,欢迎各位在评论区讨论。    

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

本地搭建xss平台并获取cookie演练

前言 一般而言&#xff0c;搭建xss平台是不被允许的&#xff0c;但是由于教育的目的&#xff0c;搭建xss平台更能让学习者更加直观感受xss漏洞对我们的危害和它的重要性。 搭建xss平台 1.搭建xss平台的基础是在phpstudy一个集成环境上的&#xff0c;所有第一步要安装phpstudy&a…

ardupilot 及PX4姿态误差计算算法对比分析

目录 文章目录 目录摘要1.APM姿态误差计算算法2.PX4姿态误差计算算法3.结论摘要 本节主要记录ardupilot 及PX4姿态误差计算算法差异对比过程,欢迎批评指正。 备注: 1.创作不易,有问题急时反馈 2.需要理解四元物理含义、叉乘及点乘含义、方向余弦矩阵含义、四元数乘法物理含…

Linux环境基础开发工具使用

目录 1.Linux软件包管理器yum 什么是软件包 关于 lrzsz 查看软件包 2.Linux开发工具 2.1.vim的基本概念 2.2vim的基本操作 2.3vim命令模式命令集 1.插入模式 2.从插入模式切换为命令模式 3.移动光标 4.删除文字 5.复制 6.替换 7.撤销上一次的操作 8.更改 2.4v…

Windows10笔记本亮度调节按键失灵

操作&#xff1a;任务管理器 -> 监视器 -> 右键点击 -> 通用即插即用监视器 -> 更新驱动程序 -> 浏览我的电脑以查找我的驱动程序 -> 让我从计算机上的可用驱动程序列表中选取 -> 点击通用即插即用监视器 -> 点击关闭 -> 重启电脑。 第一步&#x…

第三百八十二回

文章目录 1. 概念介绍2. 使用方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在上一章回中介绍了"如何修改按钮的形状"相关的内容&#xff0c;本章回中将介绍NavigationBar组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

波奇学Linux:进程通信之命名管道

进程通信的前提&#xff1a;让不同的进程看到同一份文件 匿名管道只能具有血缘关系的进程&#xff0c;毫不相关的进程通信得要命名管道 管道文件不需要刷盘&#xff0c;基于内存级文件 命名管道通过路径文件名确定打开同一个文件&#xff0c;在匿名管道中利用父子进程。 创…

(学习日记)2024.02.29:UCOSIII第二节

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

总结:React 中的 state 状态

☝️上文提及&#xff1a;可以通过组件中的重要信息是否由组件自身 state 还是外部 prop 驱动来区分「受控组件」&「非受控组件」。 换言之&#xff0c;props 是对外的&#xff0c;state 是对内的 props&#xff1a;只读&#xff0c;父组件通过 props 传递给子组件其所需要…

AI预测福彩3D第一弹【2024年3月4日预测】

众所周知&#xff0c;深度学习算法&#xff08;AI算法&#xff09;由于其内部含有庞大数量的神经元&#xff0c;理论上能够拟合任意维度的数据&#xff0c;目前在大数据分析领域应用非常广泛&#xff0c;并且能够很好的挖掘数据规律&#xff0c;对相关数据进行预测分析。 前面一…

Tomcat源码解析(二): Bootstrap和Catalina

Tomcat源码系列文章 Tomcat源码解析(一)&#xff1a; Tomcat整体架构 Tomcat源码解析(二)&#xff1a; Bootstrap和Catalina 目录 前言一、启动类Bootstrap1、main2、init3、load与start 二、加载Catalina1、load2、start2.1、注册shutdown钩子2.2、监听shutdown命令2.3、停止…

从零开始学习Netty - 学习笔记 -Netty入门【协议设计和解析】

2.协议设计和解析 协议 在计算机中&#xff0c;协议是指一组规则和约定&#xff0c;用于在不同的计算机系统之间进行通信和数据交换。计算机协议定义了数据传输的格式、顺序、错误检测和纠正方法&#xff0c;以及参与通信的各个实体的角色和责任。计算机协议可以在各种不同的层…

【PCL】 (十六)点云距离图可视化

&#xff08;十六&#xff09;点云距离图可视化 以下代码实现点云及其对应距离图的可视化。 数据样例&#xff1a;sphere100.pcd range_image_visualization.cpp #include <iostream>#include <pcl/range_image/range_image.h> #include <pcl/io/pcd_io.h&g…

C++11常用知识分享(二)【可变参数模板 || lambda表达式 || 包装器】

目录 一&#xff0c;可变参数模板 1. 递归方法展开参数包 2. 逗号表达式展开参数包 3&#xff0c;可变参数模板优势 二&#xff0c;lambda表达式 1. lambda表达式语法 2. 注意点 三&#xff0c;包装器 1. bind(了解) 嗨&#xff01;收到一张超美的风景图&#xff0c;希…

C向C++的一个过渡

思维导图 输入输出&#xff0c;以及基础头文件 在c语言中我们常用scanf("%d",&n);和printf("%d\n",n);来输出一些变量和常量&#xff0c;在C中我们可以用cin;和cout;来表示输入输出。 在C语言中输入输出有头文件&#xff0c;在C也有头文件&#xff0…

#WEB前端(CCS选择器)

1.实验&#xff1a;CCS选择器 2.IDE&#xff1a;VSCODE 3.记录&#xff1a; 子代选择器、后代选择器、相邻兄弟选择器、类选择器、伪元素选择器&#xff08;鼠标悬停&#xff09;、ID选择器、调用选择器&#xff08;全选&#xff09; 4.代码&#xff1a; <!DOCTYPE html…

Vue.js 实用技巧:深入理解 Vue.set 方法

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

JMeter常用函数整理

"_csvRead"函数 csvRead函数是从外部读取参数&#xff0c;csvRead函数可以从一个文件中读取多个参数。 下面具体讲一下如何使用csvread函数&#xff1a; 1.新建一个csv或者text文件&#xff0c;里面保存要读取的参数&#xff0c;每个参数间用逗号相隔。每行表示每一组…

MATLAB:Image Processing Toolbox工具箱入门实战

目录 1.基本图像导入、处理和导出 2.实战项目一&#xff1a;利用imfindcircles()函数检测和测量图像中的圆形目标 1.基本图像导入、处理和导出 Basic Image Import, Processing, and Export- MATLAB & SimulinkThis example shows how to read an image into the worksp…

BUUCTF---[极客大挑战 2019]Http1

1.题目描述&#xff0c;在地址框输入下面的网址 2.来到页面&#xff0c;ctrlu查看源码&#xff0c;仔细观察会看到一个.php的跳转页面 3.点进去页面提示It doesnt come from https://Sycsecret.buuoj.cn 4.页面提示它不是来源于这个网址&#xff0c;我们需要用bp抓包对数据进行…

从0到1全流程使用 segment-anything

从0到1全流程使用 segment-anything 一、安装 anaconda 一、下载 anaconda 二、以管理员身份运行安装 1、勾选 Just Me 2、统一安装路径(后续 python 等包也安装至此目录) 3、勾选 add to path 然后安装即可。 三、修改 Anaconda 默认路径及默认缓存路径 Anaconda 默认下…