动态内存管理基础详解

目录

1、为什么存在动态内存分配

2、动态内存函数的介绍

2.1 malloc和free

功能:

参数和返回值:

注意事项:

tip:

2.2 calloc

 2.3 realloc函数

功能:

参数和返回值:

realloc开辟空间的两种情况

realloc会顺序采取以下措施

疑问:那realloc的返回值用原有的指针接受吗?

3、常见的动态内存错误

3.1、对NULL指针的解引用操作

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

3.3、对非动态开辟的内存进行free释放

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

3.5、对同一块动态内存多次释放

3.6、动态开辟内存忘记释放(内存泄露)开辟空间一定要释放


1、为什么存在动态内存分配

我们已经掌握的内存开辟方式有:

int a = 0;
char b[10] = {0};

但是上述的开辟空间的方式有两个特点:

  1. 空间开辟的大小是固定的。
  2. 数组在申明时,必须指定数组的长度,它所需要的内存在编译时分配。

但是对于空间的需求,不仅仅是上述的情况。有时我们需要的空间大小在程序运行的时候才知道

那数组的编译时开辟空间的方式就不能满足了。

这时候就只能采用动态内存开辟。

2、动态内存函数的介绍

2.1 malloc和free

C语言提供了一个动态内存开辟的函数——malloc

功能:

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

参数和返回值:

参数是以字节为单位的一个无符号整型,返回值是void*,指向我们开辟这块空间的指针。

注意事项:
  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc函数的返回值必须要做检查
  • 返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候由使用者自己决定。
  • 如果参数size是0,malloc的行为是标准未定义的。
tip:
  • malloc申请到空间后,直接返回这块空间的起始地址不会初始化空间的内容。
  • malloc申请的内存空间,当程序退出时,还给操作系统,当程序不退出,动态生气的内存是不会主动释放的,需要用free函数来释放。
  • 每当free函数释放空间后,指针就没有被指向的内容,为了防止野指针,需要将其设为控制在(即每次使用free函数后,都需要置成空指针
  • free函数不能释放非动态开辟的内存空间,这种行为是标准未定义的
  • 如果free函数的参数是空指针,则free函数什么都不做
int main()
{
	//int arr[10];
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//开辟成功
	for (int i=0;i<10;i++)
	{
		printf("%d\n", *(p + 1));
	}
	return 0;
}

2.2 calloc

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

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

举个例子:

 2.3 realloc函数

功能:

realloc函数的出现让动态内存管理更加灵活,调整对动态内存的大小。

参数和返回值:

ptr是要调整的内存地址,size是调整之后的新大小(以字节为单位),返回值为调整之后的内存起始位置。如果ptr为空指针,那么函数的功能与malloc函数一样。

realloc开辟空间的两种情况

1、原始空间的后面空间足够

直接返回原始空间的起始地址

2、原始空间的后面空间不够

realloc会顺序采取以下措施

(1)、开辟新的空间

(2)、会将旧的空间中的数据拷贝到新的空间

(3)、释放旧的空间

(4)、返回新空间的起始地址

疑问:那realloc的返回值用原有的指针接受吗?

回答:不能,因为假如realloc增容失败,会返回空指针,而原有的指针指向的空间还没有释放,就被置成空指针,这就造成了内存泄露!因此我们应该用一个新的指针去接受,然后判断增容是否成功,如果成功,就将新指针的内容赋给原有的指针,否则程序结束。

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		perror(malloc);
		return 1;
	}
	for (int i=0;i<2;i++)
	{
		*p = i + 1;
		p++;
		//p[i]=i+1;
	}
	int* ret = (int*)realloc(p, 80);
	if (ret == NULL)
	{
		perror(realloc);
		return 1;
	}
	p = ret;
	for (int i=0;i<20;i++)
	{
		printf("%d\n", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

 上面是正确的使用realloc增容的方式。如果减容,直接size输入一个小于原来的值即可。

3、常见的动态内存错误

3.1、对NULL指针的解引用操作

解决方法:判断内存开辟函数malloc/calloc/realloc返回值是否为空

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

3.3、对非动态开辟的内存进行free释放

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

 注意此时的p指向的不是我们动态开辟空间的起始地址,而是后面相当于动态内存的一部分,此时再用free释放是不对的,free释放应该从动态内存的起始地址开始释放

不能让起始指针跑偏! 

3.5、对同一块动态内存多次释放

3.6、动态开辟内存忘记释放(内存泄露)开辟空间一定要释放

解决方法:

动态内存申请的空间不会出了作用域自动销毁,只有两种方式销毁(将内存还给操作系统):退出程序和free函数。

malloc和free函数成对使用

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

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

相关文章

Rust操作MySQL

查询 本部分是对 「Rust入门系列」Rust 中使用 MySQL[1]的学习与记录 经常使用的时间处理库&#xff1a; chrono 流式查询使用&#xff1a; query_iter 输出到Vec使用&#xff1a; query 映射到结构体使用&#xff1a; query_map 获取单条数据使用&#xff1a; query_first 命名…

Hadoop简介以及集群搭建详细过程

Hadoop简介以及集群搭建详细过程 hadoop集群简介hadoop部署模式Hadoop集群安装1.集群角色规划2.服务器基础环境准备3.上传安装包hadoop安装包目录结构5.编辑hadoop配置文件6.分发安装包7.配置hadoop环境变量8.NameNode format(格式化操作) hadoop集群启动关闭-手动逐个进程启停…

漏洞复现-yapi远程执行命令漏洞复现

目录 漏洞原理漏洞发现漏洞描述影响范围 yapi学习漏洞复现环境搭建exp 入侵检测与防御参考 漏洞原理 漏洞发现 查看issue2229 漏洞描述 网站开放注册功能时可随意注册&#xff0c;设置全局mock脚本可执行任意代码。 影响范围 Yapi < 1.9.2 yapi学习 YApi 是高效、易…

vue3前端分页,全选翻页状态保持

直接贴代码&#xff0c;代码中有注释 <template><div class"viewer-container" id"viewer-container"><!-- 表格 --><el-table:row-key"getRowKeys":data"data.tableDataCopy"style"width: 100%"ref&…

Spring详解(学习总结)

目录 一、Spring概述 &#xff08;一&#xff09;、Spring是什么&#xff1f; &#xff08;二&#xff09;、Spring框架发展历程 &#xff08;三&#xff09;、Spring框架的优势 &#xff08;四&#xff09;、Spring的体系结构 二、程序耦合与解耦合 &#xff08;一&…

消息队列——rabbitmq的不同工作模式

目录 Work queues 工作队列模式 Pub/Sub 订阅模式 Routing路由模式 Topics通配符模式 工作模式总结 Work queues 工作队列模式 C1和C2属于竞争关系&#xff0c;一个消息只有一个消费者可以取到。 代码部分只需要用两个消费者进程监听同一个队里即可。 两个消费者呈现竞争关…

【itext7】itext7操作PDF文档之添加段落文本内容、添加List列表、添加Image图片、添加Table表格

这篇文章&#xff0c;主要介绍itext7操作PDF文档之添加段落文本内容、添加List列表、添加Image图片、添加Table表格。 目录 一、itext7操作PDF内容 1.1、添加段落文本内容 1.2、添加列表内容 1.3、添加图片 1.4、添加表格 &#xff08;1&#xff09;列宽采用点单位&#…

情绪即需求

情绪即需求 心理学认为&#xff0c;每个情绪背后都藏着一个未被满足的心里需求. 模型介绍 每一个情绪背后&#xff0c;都有一个未被满足的心理需求。情绪没有好坏之分&#xff0c;存在即合理。情绪是人类不断进化的产物&#xff0c;每一种情绪都是在保护我们&#xff0c;都有其…

基于Java+SpringBoot+vue前后端分离校园周边美食探索分享平台设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

OpenCv之特征检测

目录 一、基本概念 二、harris角点检测 三、SIFT算法 四、Shi-Tomasi角点检测 一、基本概念 特征检测指的是使用计算机提取图像信息&#xff0c;决定每个图像的点是否属于一个图像特征。特征检测的结果是把图像上的点分为不同的子集&#xff0c;这些子集往往属于孤立的点、…

Element Plus 日期选择器

计算开始日期到结束日期的总天数 结构 <el-form-item label"计划开始时间" required prop"StartTime"><el-date-pickertype"date"v-model"ruleForm.StartTime":disabled-date"StartTime"placeholder"计划开始…

图像处理之LoG算子(高斯拉普拉斯)

LoG算子&#xff08;高斯拉普拉斯算子&#xff09; LoG算子是由拉普拉斯算子改进而来。拉普拉斯算子是二阶导数算子&#xff0c;是一个标量&#xff0c;具有线性、位移不变性&#xff0c;其传函在频域空间的原点为0。所有经过拉普拉斯算子滤波的图像具有零平均灰度。但是该算子…

RT-Thread qemu mps2-an385 bsp 移植制作 :系统运行篇

前言 前面已经让 RT-Thread 进入了 entry 入口函数&#xff0c;并且 调整 链接脚本&#xff0c;自动初始化与 MSH shell 的符号已经预留&#xff0c; 进入了 RT-Thread 的初始化流程 接下来&#xff1a;从 内存管理、系统tick 定时器、适配串口 uart 驱动三个模块入手&#xf…

CPU密集型和IO密集型任务的权衡:如何找到最佳平衡点

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、CPU密集型与IO密集型3.1、CPU密集型3.2、I/O密…

【字符流】案例:集合到文件

案例&#xff1a;集合到文件 1.需求&#xff1a; 把ArrayList集合中的字符串数据写入到文本文件。要求&#xff1a;每一个字符串元素作为文件中的一行数据 2.思路 创建ArrayList集合往集合中存储字符串元素创建字符缓冲输出流对象遍历集合&#xff0c;得到每一个字符串数据调…

SpringBoot中间件—ORM(Mybatis)框架实现

目录 定义 需求背景 方案设计 代码展示 UML图 实现细节 测试验证 总结 源码地址&#xff08;已开源&#xff09;&#xff1a;https://gitee.com/sizhaohe/mini-mybatis.git 跟着源码及下述UML图来理解上手会更快&#xff0c;拒绝浮躁&#xff0c;沉下心来搞 定义&#x…

界面控件DevExpress WPF数据编辑器组件,让数据处理更灵活!(二)

界面控件DevExpress WPF编辑器库可以帮助用户提供直观的用户体验&#xff0c;具有无与伦比的运行时选项和灵活性。WPF数据编辑器提供了全面的掩码和数据验证支持&#xff0c;可以独立使用&#xff0c;也可以作为容器控件(如DevExpress WPF Grid和WPF TreeList)中的单元格编辑器…

【pytho】request五种种请求处理为空和非空处理以及上传excel,上传图片处理

一、python中请求处理 request.args获取的是个字典&#xff0c;所以可以通过get方式获取请求参数和值 request.form获取的也是个字典&#xff0c;所以也可以通过get方式获取请求的form参数和值 request.data&#xff0c;使用过JavaScript&#xff0c;api调用方式进行掺入jso…

Cmake笔记记录

工作后开发内容都是在Linux系统下完成&#xff0c;cmake使用比较频繁&#xff0c;找到一篇很不错的CMake笔记。 记录下来方便自己查阅。 目录 1.CMake介绍2.示例一&#xff1a;编译单个文件CMAKE_BUILD_TYPE 3.示例二&#xff1a;编译同个目录下多个文件aux_source_directory()…

QT通过TCP协议发送结构体数据

文章目录 前言1. memcpy方式1.1 发送整个结构体1.2 发送部分数据 2. QDataStream2.1 符号<<2.2 wrieteRawData 总结 前言 做上位机的时候下发数据&#xff0c;数据是一个结构体&#xff0c;这里就阐述一下怎么通过TCP协议发送结构体。 我自己写的时候主要通过两种方式&a…