动态内存管理(1)

news2025/1/15 22:35:36

TIPS

1. 

2. malloc, free, calloc, realloc 这些的基本前提都是在内存堆区

内存堆区不能与内存栈区两者混淆乱套 


动态内存管理存在的原因

1. 为什么要有动态内存管理?其实我们之前学过比如说对内存的管理,比方说我申请一块内存空间:
1.1  有一种普通的方式int a = 10; 这一种是固定的向内存申请四个字节/申请一个变量的空间;
1.2  还有一种方式就是申请连续的一块空间,如:int arr [10];   

2. 这两种申请开辟内存空间的方法都是可以的,但是都有一个缺点,一旦把空间申请好,这个空间的大小是不能变与修改了的。因此这些内存的申请与使用的方式有局限性。 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
3. C语言里面给我们提供一种方式,让我们向内存申请空间,然后申请到空间之后我就去用。当我不够的时候,内存空间可以变长;当我觉得多了的时候,这个内存空间可以变小。这个就是动态内存管理。

(变长数组不是说你能把数组给它随意的变长变短,只是在一开始你可以用一个变量指定数组元素的个数,一旦开辟好内存空间之后,也就不能发生变化了)

4.  动态内存管理指的是向内存申请空间之后,根据我实际用的情况,我可以让这个空间可以变大,也可以变小。非常灵活,适配度高。

内存简单介绍

1.  

2. 内存分为几个区域,有栈区,堆区与静态区(这是我们学语言的时候划分的区域,实际上更为复杂)。栈区里面放的是局部变量/数组,函数的形式参数,反正都是临时的变量.... 这里面的东西都是进入作用域创建,一旦出了作用域就会销毁
3. 还有一个区域是堆区,这个堆区是malloc, calloc, realloc所操作的内存空间,都是在堆区上的。堆区上我们来干什么?就是来进行动态内存分配/管理的。我们进行动态内存管理申请与释放的空间都是在堆区里面的
4. 而在静态区里面,放的是静态变量,全局变量。今天我们学的函数都是针对堆区而言,操作空间都是在堆区,申请与释放的内存空间都是在堆区里面。 

malloc()函数 

 

1. malloc是用来向堆区申请一块内存空间。
2. malloc就是向内存堆区(是在堆上)申请一个size字节的内存空间,然后返回一个指向这个内存空间的起始位置的指针(void*)
3. malloc只是负责向堆区申请size字节的空间,至于里面放什么我也不知道。所以返回指针的时候,这个时候的类型无法确定,所以是瞎子垃圾桶void*(没有具体类型的指针)
4. malloc堆区内存申请完之后,会返回一个void*的指向起始位置的指针。按道理来说,我接受的时候也应该用void*接受。但是这样子的话,在后面我用的时候我都要进行强制类型转换不太方便。事实上,我们在申请内存的时候不会糊里糊涂,在事先肯定要想清楚里面放什么的,因此比如说不如直接拿整型指针接受,把malloc前面强制类型转换。 

5. malloc申请失败的话,返回NULL,因此要对返回值进行判断。这时候如果库函数malloc调用失败,就会把错误码放入errno,然后我用strerror去接受errno解读错误信息并用printf打印即可。
6.如果malloc申请成功后,那该怎么使用这个空间呢?首先得知道: malloc向堆区申请的是一块连续的空间并且有了起始地址,因此可以把它当成数组来访问( 利用偏移量....*(p+i)在赋值即可) 
7. 在堆区里面,你要的时候用malloc申请空间了,那你到底要不要还一下?如果不还的话会有隐患,如果不还给操作系统,程序在运行结束的时候也会被操作系统回收。那如果这个程序运行一直不结束,你不用了之后又不主动去还,那你就是占着茅坑不拉屎了,这块内存空间相当于是限制与浪费了。
8. 这个时候有一个函数叫做free()。free是释放申请的内存 

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

注意点:

1. 参数里面是向堆区申请开辟的字节个数勤用sizeof(),如10*sizeof(int) 

2. 判断malloc返回结果是否为空指针, 可以搭配errno与strerror()

3.  将malloc返回指针强制类型转换除非你糊里糊涂的)

4.  free()归还与指针置空

free()函数

 

1. free(p),将p指向的那块堆区内存空间释放/还给操作系统,但不受影响,还是指向原先的位置
2. 但是虽然把p指向的堆区空间还给操作系统了,但是这个指针p还存着原先那个空间的起始地址,这就不合适了。万一有人*p(解引用),这时候就形成了非法访问。

3. 因此需要主动把p = NULL置空,因为对空指针而言,无法进行解引用操作了

4.  如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的,如果参数 ptr 是NULL指针,则函数什么事都不做。

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

calloc()函数

 

1. calloc也是可以用来开辟空间,但是函数原型与malloc不同。
2. calloc是向堆区为num个元素开辟的内存空间,每个元素占size个字节
3. calloc开辟空间后的返回指针与void*、合理指针接受形式、失败后NULL的预先判断都是与malloc雷同的,失败后可以用strerror(errno)+printf或者直接perror()就可以返回错误信息
4. calloc向堆区申请空间之后,用完了也需要free(p)并且将原先的指针p置空。 

注意点:

1. 参数里面为numsize勤用sizeof(),如10, sizeof(int) 

2. 判断calloc返回结果是否为空指针, 可以搭配errno与strerror()

3.  将calloc返回指针强制类型转换除非你糊里糊涂的)

4.  free()归还与指针置空

malloc()与calloc()的区别 

1. 在参数上面有区别。malloc是直接我先计算好然后传给malloc一个总大小(单位是字节)就可以,而calloc是需要开辟多少个元素每个元素多少字节的这么一个内存空间
2. 其次就是malloc申请到堆区空间后,不会初始化里面是随机值,直接返回起始地址;而calloc申请到空间之后,会把里面全部初始化为0
3. 也正是因为如此,malloc效率更高。 

 

 

所以malloc申请到空间之后不会初始化,而calloc申请到空间之后会初始化成0

接下来也可以侧面证明free释放了空间还给操作系统了

  

realloc()函数 

 

1. 我们之前讲过:动态内存分配可以让空间变大变小,可以根据实际情况来看. 而前面的malloc与calloc还有free都还没有讲到调整,调整的大任应该交到realloc头上
2. 参数为指针ptr和sizerealloc调整ptr所指向的堆区空间,并且要输入你希望调整后新的空间大小是多少
3. realloc在帮你把空间调整好之后,也会返回一个void*指针(指向起始地址)

6. 但是呢,realloc函数的使用比我们的想象还要更加复杂一些,当realloc使用之后返回的指针不能用原先的指针去接受,需要用一个新的指针去接受。接受的形式与malloc一样,先强制类型转换(除非你是糊里糊涂的)。 

realloc()工作原理 

1. (情形一)realloc在调整空间的时候,比如说把原先的空间加长,这时候首先要看原先空间后面。如果后面还有一大片没有被使用的空间(支持你去扩容),那是相当于是允许加长操作的。那么我就在原先开辟的内存空间屁股后面去追加另需要的空间同时我追加完之后还是返回旧的指针。这个时候只是后面的空间多了。我的起始地址并没有发生变化,返回的还确实是旧的指针。


2. (情形二)比如说我要用realloc去加长原先开辟的空间,可是在原先空间的屁股后面,已经被别人占用了,这时候如果你继续在原先空间的屁股后面扩容的话,就把别人的空间给覆盖与破坏了。这时候realloc就会在内存当中重新找一块满足需求大小的空间。把旧的空间里面的数据在搬过来/拷贝到新空间前面的位置,搬过来之后把旧的空间释放掉还给操作系统。然后返回新的空间起始地址处的指针。  

 

3. (情形三)realloc函数在申请空间扩容失败的时候。失败的话直接返回空指针。这也就解释了为什么realloc的返回类型不能用旧的那个指针去接受(上面两种情形还真不能给你解释,这种情形可以解释了)因为一旦扩容失败,realloc返回NULL,然后把NULL赋给旧的那个指针,好了旧的那个指针现在不指向原先的起始地址处了指向0地址去了,你realloc扩容失败后还把人家原先的数据搞丢

,p再也想不起来它曾经维护的那个空间了。  

小注意点:

1. 如果realloc的第一个参数是NULL,那么它相当于就是malloc()

2. 先把realloc的返回值用新指针接受,然后去判断一下这个新指针是不是空指针,如果不是的话,再把这个新指针的地址赋给旧指针,这时候旧指针就在维护扩容之后的空间了。

调试一下,总结一下

开判用调回 

 

 

 

常见的动态内存错误 

1.  对空指针NULL进行解引用操作

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

 

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

 

4. 对非动态开辟内存使用free释放 

 

放在栈区的内存空间跟free一点关系都没有,free是去释放堆区上的空间的 

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

使用free释放一块动态开辟内存的一部分
就是说你这个
free释放的指针必须是指向这块动态开辟内存的起始地址

6.  对同一块动态内存多次释放

 

7. 动态开辟内存忘记释放(内存泄漏) 

涉及到函数里面(记性差)

 

涉及到函数内外部联系的问题

一个函数里面,可能有些东西是在内存栈区的,有些东西是在内存堆区的。比如说:函数形参,临时变量,局部变量,指针等这些都是在栈区的,跟堆区半毛钱关系没有,而比如说你用malloc开辟的空间是在内存堆区) 

1. 内存栈区里面进入作用域时开辟的空间出了作用域之后就自动会销毁还给操作系统
2. 而堆区里面你函数里面动态开辟的内存出了函数之后你还是在的,不会还给操作系统,这时候如果你函数里面没有释放的话,一定要返回一个指向空间起始地址的指针,谁申请了空间谁释放,你如果不释放,你也要告诉别人我这边申请过了,你回头去释放

3. 我在函数出来后外边进行释放,如果不返回指针,函数出来后临时变量全部销毁,没有人记得这块空间了,但它还没有还给操作系统了呢。从这个函数里面走出来之后,由于指向这块空间的指针已经被销毁了。所以没人记得这块空间了,这时候想释放都来不及了

这就是内存泄露,操作系统把控的内存被少了去了,malloc申请空间从来不释放,一直在吃内存

内存泄露(动态内存的空间忘记释放了,这被称为内存泄露)
1. 你不用了
2. 你又不释放
3. 别人也用不上
4. 这块空间回头又可能找不上了 

最后,有几个调试技巧我还不知道,这边记录一下:

1. 按一下这个,调试的时候就直接会来到此处 

  

2. 要在监视窗口观察指针指向的内存堆区的空间时,可以用逗号 

 

 

 

 

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

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

相关文章

任意方向边界框——day64 读论文:基于自适应目标定位特征卷积神经网络的高分辨率遥感影像多面向目标检测

Multi-Oriented Object Detection in High-Resolution Remote Sensing Imagery Based on Convolutional Neural Networks with Adaptive Object Orientation Features 基于自适应目标定位特征卷积神经网络的高分辨率遥感影像多面向目标检测1. Introduction2. Materials and Met…

jQuery ajax中dataFilter的用法

参考资料 jquery的ajax的dataFilter参数的使用 ⏹用于处理 XMLHttpRequest 原始响应数据的函数 运行在success函数之前, 对Ajax请求返回的原始数据进行预处理 可以对返回的json数据中的null属性进行过滤可以对返回的json数据添加一些自定义的属性 如果不返回原始数据,返回其他…

零代码连接邮箱腾讯云企业网盘,附件管理超轻松

在日常工作中&#xff0c;想必大家每天都会收到各种各样的工作邮件&#xff0c;并且很多重要的文件材料也是通过邮件附件的形式来传输的&#xff0c;那么如何一站式管理这些文件&#xff0c;对于提高办公效率就至关重要了。关于邮件附件管理&#xff0c;相信大家也都碰到过这样…

全面了解文件上传漏洞, 通关upload-labs靶场

靶场简介 upload-labs是一个专门用于学习文件上传漏洞攻击和防御的靶场。它提供了一系列模拟文件上传漏洞的实验环境&#xff0c;用于帮助用户了解文件上传漏洞的原理和防御技术。 这个靶场包括了常见的文件上传漏洞类型&#xff0c;如文件名欺骗、文件类型欺骗、文件上传功能…

1582_C代码实现的快速、可移植MD5信息摘要算法

全部学习汇总&#xff1a; GreyZhang/c_units: A small piece of code which can be reuse anywhere, I call it a unit. This is a collection of unit in C language! Ok, yes, it would be my toolbox. (github.com) 工作之中&#xff0c;同事用到了MD5信息摘要算法&#x…

面试加分题--socket是否是并发安全的?

今天和大家聊一个有点儿东西的面试题&#xff1a;socket是否是并发安全的&#xff1f; 为了帮助大家理解&#xff0c;我们先假设一个场景。 就拿游戏架构来说&#xff0c;我们想象中的游戏架构是下面这样的。 想象中的游戏架构 也就是用户客户端直接连接游戏核心逻辑服务器&…

解决⾃动驾驶中计算机视觉的⽬标检测问题

来源&#xff1a;投稿 作者&#xff1a;cairuyi01 编辑&#xff1a;学姐 最近读了《Object detection with location-aware deformable convolution and backward attention filtering》&#xff0c;这是⼀篇2019年刊登在CVPR上的CV论⽂。与解决普适性的CV任务不同&#xff0c…

SpringMVC如何优化Ajax技术

SpringMVC如何优化Ajax技术&#xff1f; AJAX Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 AJAX 是一种在无需重新加载整个网页的情况下&#xff0c;能够更新部分网页的技术。 Ajax 不是一种新的编程语言&#xff0c;而是一种用于创…

EIoU和Focal-EIoU Loss

1、论文 论文题目&#xff1a;《Focal and Efficient IOU Loss for Accurate Bounding Box Regression》 2、引言 CIoU Loss虽然考虑了边界框回归的重叠面积、中心点距离、高宽比。但是其公式中的v反映的是高宽的差异&#xff0c;而不是高宽分别与其置信度的真实差异。因此&…

蚂蚁智能内容合规审核产品探秘

随着互联网服务的不断深化&#xff0c;产品营销的形式从传统文本、长图文&#xff0c;增加到短视频、直播等新媒介形态&#xff0c;展现形式愈加丰富的同时&#xff0c;也为营销宣传内容合规审核带来了诸多难题。如何解决与日俱增的审核量与合规审核人员有限之间的矛盾&#xf…

【阶段三】Python机器学习31篇:机器学习项目实战:基于皮尔逊相关系数搭建电影智能推荐系统

本篇的思维导图: 项目背景 在当今这个大数据时代,智能推荐系统的应用越来越广泛,网上购物、在线观影、新闻推送的背后都有智能推荐系统算法的支持。人们经常会在视频平台上观看电影,有时明确想要观看某部电影,有时则仅仅是随机搜寻。如果视频平台能利用基于物品的…

DDOS攻击

把我掘金的文章同步一份过来 最近网上爆火的一款游戏 Goose Goose Duck (鹅鸭杀) 游戏官方在近日发布了一则公告&#xff0c;宣布由于服务器屡次遭受黑客攻击&#xff0c;该游戏服务器将暂时关服三天进行维护 遭到了DDOS攻击&#xff0c;背后原因&#xff0c;我们不做讨论&…

代码随想录算法训练营第十七天二叉树 java : . 110.平衡二叉树 257.二叉树的所有路径 404.左叶子之和

文章目录前言Leetcode 110.平衡二叉树题目讲解思路Leetcode 257. 二叉树的所有路径题目讲解这道题涉及到了回溯Leetcode 404.左叶子之和题目讲解总结前言 选择一个简单的理念&#xff0c;矢志不渝地去执行&#xff08;Take one simple idea and take it seriously 递归三部曲…

【Nginx】Nginx搭建高可用集群

1. KeepalivedNginx 高可用集群&#xff08;主从模式&#xff09;2. 配置高可用的准备工作3. 在两台服务器上安装keepalived4. 完成高可用配置(主从配置)5. 最终测试 1. KeepalivedNginx 高可用集群&#xff08;主从模式&#xff09; 2. 配置高可用的准备工作 需要两台服务器…

Revit如何将明细表导出为DWG格式【批量导出图纸】

一、Revit中怎样将明细表导出到DWG文件中 有时需要将Revit中生成的各种明细表导入到CAD中使用&#xff0c;但是在明细表视图中并没有导出成DWG格式的选项如图1所示&#xff0c;应该如何操作才能导出成CAD可识别文件呢&#xff1f; 方法一&#xff1a;将明细表通过导出为报表选项…

Java 核心技术卷 I 基础知识笔记(一)

Java 的基本程序设计结构 2.1 一个简单的 Java 应用程序 一个最简单的 Java 应用程序&#xff0c;它只发送一条消息到控制台窗口中&#xff1a;/*** This is the first sample program in Core Java Chapter 3* version 1.01 1997-03-22* author Gary Cornell*/ public class…

分享111个Java源码,总有一款适合您

Java源码 分享111个Java源码&#xff0c;总有一款适合您 源码下载链接&#xff1a;https://pan.baidu.com/s/1fycjYHA7y6r-IH8H7v5XKA?pwdag8l 提取码&#xff1a;ag8l 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff…

网络编程学习记录

服务端首先是确定协议版本。首先定义一个结构体 WSADATA wsadata; 这个结构体是啥呢&#xff1f; 是Windows下得到广泛应用的、开放的、支持多种协议的网络编程接口。大家晓得了吧。 让我们看看这个结构体。 typedef struct WSAData {WORD wVersion; …

c++ socket之io复用模型 epoll进阶

服务器开发系列 文章目录服务器开发系列前言一、socket epoll介绍二、代码实现1. epoll client实现2. epoll server实现3. epoll client server验证总结前言 I/O复用模型&#xff1a;主要是指&#xff0c;一个线程可以同时监控多个系统IO、并且能够操作多个系统IO的一种技术模…

西瓜书第一章课后题答案(一)

1.1 针对西瓜分类分题进行讲解属性&#xff1a; 3个属性色泽&#xff1a;&#xff08;青绿&#xff0c;乌黑&#xff0c;浅白&#xff09;根蒂&#xff1a;&#xff08;蜷缩&#xff0c;硬挺&#xff0c;稍蜷&#xff09;敲声&#xff1a;&#xff08;浊响&#xff0c;清脆&…