动态内存函数的使用和综合实践-malloc,free,realloc,calloc

 

什么是动态内存

动态内存是指在程序运行过程中可以被分配和释放的内存空间。这与静态内存分配相对,静态内存分配是在程序编译时就已经确定的内存空间,其大小在程序运行期间固定不变。
在许多编程语言中,特别是在C语言中,动态内存管理是通过一系列标准库函数来实现的,如`malloc()`、`calloc()`、`realloc()`和`free()`。这些函数提供了在程序运行时请求和释放内存的能力。
动态内存的分配通常发生在堆(Heap)区域,这是程序内存空间的一个部分,用于存储动态分配的内存。与之相对的还有栈(Stack),栈是用于存储函数调用信息和局部变量的内存区域,其分配和释放是自动的,通常在函数调用开始和结束时进行。
动态内存管理的意义在于它提供了灵活性,允许程序在运行时根据需要分配和释放内存,这对于实现复杂的数据结构和算法、优化资源使用、以及处理不确定大小的数据集等方面至关重要。然而,同时它也要求程序员必须谨慎使用,避免内存泄漏和野指针等问题。

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

 malloc(申请函数)free(释放函数)

 malloc和free的语法格式

`malloc` 函数是 C 语言标准库中的一个重要函数,用于动态分配内存。其语法如下:


void *malloc(size_t size);


这里的 `void *` 表示返回的是一个 `void` 类型的指针,实际上这个指针指向的是一个 `char` 类型的内存块。`size_t` 是一个无符号整数类型,用于指定分配的内存大小。
当你调用 `malloc` 函数时,你需要提供一个参数 `size`,表示你需要分配的内存的大小(以字节为单位)。函数返回一个指针,指向为你分配的内存区域的开始位置。如果分配成功,这个指针不会是 `NULL`;如果分配失败(比如,系统没有足够的内存来满足请求),`malloc` 函数会返回 `NULL`。
在使用 `malloc` 分配的内存时,你需要使用 `memcpy`,`strcpy` 等函数来复制数据到这个内存区域,而不是 `strcpy`,`printf` 等函数,因为这些函数不适用于动态分配的内存。
在使用完动态分配的内存后,你应该使用 `free` 函数来释放内存,以避免内存泄漏。


free(void *ptr);


这里的 `ptr` 是之前 `malloc` 或其他动态内存分配函数(如 `calloc`,`realloc`)返回的指针。使用 `free` 后,指针所指向的内存将被释放,可以被系统重新分配给其他请求。但是,免费的内存不会立即变得可被其他程序使用,这是一个操作系统和硬件相关的过程。

这里是需要把这两个函数放到一起讲解的,因为申请内存空间你就得释放内存空间,不然会导致内存泄漏,内存泄漏会导致电脑内存里面可以使用的空间越来越少。最后导致崩盘。

———————————————————————————————————————————

malloc和free函数的使用 

申请内存空间

返回函数 一定要做检查

头文件stdlib.h

perror打印出错误

动态内存的开辟空间都在堆区


释放内存

传递的参数 p就可以

解释一下

所以 此时释放的是自己的权限

但是需要知道的是 此时p也就是野指针了

所以此时我们把p栓到树上

也就是设置为空指针

———————————————————————————————————————————

 这里开辟内存空间注意的三点(重点)

1

这里需要进行强制类型的转化因为从语法格式我们可以看出来,这里是的void*类型,也就是不明确的类型,为什么,因为C语言官方在设定的时候不清楚你开辟内存空间的目的是干什么用的,不知道是用于整数的存储,还是用于字符的打印,还是干什么。所以这里给出无返回类型,只需要你在使用的时候进行强制类型转化就可以。这样可以提升代码的兼容性和健壮性。

2.

对于空间的释放,释放空间之后尽量的让指针指向NULL,也就是空指针,因为当指针指向的空阿金释放之后,本质上他是不指向任何的数值了,也就是此时他是野指针了,虽然你不使用他了,但是最好指向空指针。防止内存的泄露

3.

使用空间的时候,你不能让指针跟着走,我们可以看到代码里面,

使用的是这个代码*(p+i)=I+1;。而不是*(p)=i;p++;这样的代码。

为什么,因为当指针走远之后,你进行释放空间的时候,本质上释放的是指针移动后指向的空间,你让指针一直移动,移动到开辟的空间的最后一个位置,然后再进行释放空间的时候,其实本质上释放的是开辟空间之后的空间,也就是没有释放空间。

你创建了空间,但是没有释放空间,此时会导致内存泄露。

内存泄露的问题我们也聊过,也就是内存占用少的时候还不明显,但是当有大量程序运行的时候,就会导致内存一直占用,但是得不到释放。从而导致崩盘。

4.

malloc函数里面放置的是字节大小,这里放置的是字节大小,不是bit大小,这里一定要记住。

———————————————————————————————————————————

malloc和free代码

int main()
{//malloc不初始化开辟空间//开辟20个字节的空间大小 int* p = (int*)malloc(5 * sizeof(int));if (p == NULL){perror("malloc:");//这里是打印错误信息,return 1;}for (int i = 0; i < 5; i++)//这里是打印出来开辟的空间 赋值之后进行打印 {*(p + i) = i + 1;//这里是进行赋值 赋值从1开始printf("%d ", *(p + i));//这里是打印出来}free(p);//这里进行指针的释放p = NULL;//防止野指针的问题,我们指向空指针return 0;
}

malloc第两种写法

可以是sizeof(int)=四个字节

然后5*sizeof(int)=20个字节

第二种就是上述的写法malloc(20)

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

 calloc(申请空间初始化

calloc(申请空间初始化)

语法格式

在C语言中,`calloc` 和 `realloc` 是用于动态内存分配的两个函数。它们都定义在头文件 `<stdlib.h>` 中。

1. `calloc`

函数用于在内存的动态存储区分配空间,并初始化每个字节为 0。其函数原型如下:


void *calloc(size_t num, size_t size);

- `num`: 分配块的数量。
- `size`: 每个块的大小(以字节为单位)。
`calloc` 返回一个指向分配内存的指针。如果分配失败,则返回 `NULL`。

———————————————————————————————————————————

calloc函数的使用

 我们直接看是不直观的,我们可以这样理解

malloc(5*sizeof(int))=calloc(5,sizeof(int))

这两个是等价的 

calloc函数其实和malloc函数本质都是一样的唯一不一样就是,calloc函数在开辟空间的时候会进行初始化,当然 calloc函数初始化,那运行速度也会比malloc慢一点。malloc函数初始化, 会快一点

其他的没区别

——————————————————————————————————————————— 

calloc和free代码

int main()
{//malloc不初始化开辟空间//开辟20个字节的空间大小 int* p = (int*)calloc(5 , sizeof(int));if (p == NULL){perror("malloc:");//这里是打印错误信息,return 1;}for (int i = 0; i < 5; i++)//这里是打印出来开辟的空间 赋值之后进行打印 {//*(p + i) = i + 1;//这里是进行赋值 赋值从1开始printf("%d ", *(p + i));//这里是打印出来}free(p);//这里进行指针的释放p = NULL;//防止野指针的问题,我们指向空指针return 0;
}

这里我们可以看到和malloc一模一样,只是换了一下函数,其他是没有变化的。 

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

realloc(动态内存二次的大小调整,也就是调整空间大小)

语法格式

1. `realloc`

函数用于动态地改变之前分配的内存块的大小。其函数原型如下:


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

- `ptr`: 指向之前分配的内存块的指针。如果 `ptr` 为 `NULL`,那么 `realloc` 行为与 `malloc` 相同。
- `size`: 新分配的大小(以字节为单位)。
`realloc` 可以调整内存块的大小,如果新的大小比原来小,那么内存块可能会被移动。如果新的大小比原来大,那么内存块会尝试扩展。如果扩展失败,那么原来的内存块会被保留,只是其大小变为新的大小。`realloc` 返回一个指向调整大小后的内存块的指针。如果调整大小失败,则返回 `NULL`。
在使用这些函数时,应当总是检查返回的指针是否为 `NULL`,以避免潜在的空指针引用错误。并且在使用 `calloc` 或 `realloc` 分配的内存后,应当在不再需要时使用 `free` 函数来释放内存,以避免内存泄露。

———————————————————————————————————————————

realloc函数的使用 

这个函数的代码格式可以理解为 ,你之前malloc或者calloc申请的空间是p指针进行接收的,OK此时你想对这个空间进行空间的扩展,那此时的ptr也就是p指针变量,size也就是你需要的实际空间,这里的空间不是扩展的空间,而是实际的空间
void *realloc(void *ptr, size_t size);

也就是realloc(p,40)

之前我们p开辟的是20的空间 ,这里我们实际需要的是40的空间,这不是再开辟40空间,而是一共40 的空间。

下面解释一下为什么

———————————————————————————————————————————

realloc函数扩展空间的原理

 realloc函数扩展空间几乎就是两种模式

1. 直接在原内存空间的基础上进行扩展内存

2. 把原空间的内存复制到新的内存空间,建立一个更大的内存空间,需要知道的是,只要是进行内存的复制,那么就有可能导致复制失败,从而导致数据丢失。

所以实际使用的时候,我们还是需要进行判断语句的。

 如图1

如图2 

———————————————————————————————————————————

realloc代码解析 

首先我们创建一个空间 ,然后进行调整 

因为这里使用的时候 是有可能导致开辟空间错误,导致地址的丢失,所以我们进行判断,也就是主动的找一个指针变量指向新开辟的地址,只要指向的空间不是空指针,那么也就是可以满足条件,然后进行一个二次赋值

最后,不使用的时候进行申请空间的清理,防止内存空间的泄露

———————————————————————————————————————————

realloc代码 

int main()
{//malloc不初始化开辟空间//开辟20个字节的空间大小 int* p = (int*)calloc(5 , sizeof(int));if (p == NULL){perror("malloc:");//这里是打印错误信息,return 1;}for (int i = 0; i < 5; i++)//这里是打印出来开辟的空间 赋值之后进行打印 {//*(p + i) = i + 1;//这里是进行赋值 赋值从1开始printf("%d ", *(p + i));//这里是打印出来}free(p);//这里进行指针的释放p = NULL;//防止野指针的问题,我们指向空指针//首先我们已经开辟动态内存空间 但是不能满足我们的需求,那么此时我们就用realloc进行空间的扩展//依旧是采取强制类型转化,然后我们这里是延伸到40个字节的空间//因为我们知道,开辟空间的时候可能会导致内存空间的扩展失败//所以我们不能直接p=realloc(int*)realloc(p, 10 * sizeof(int)); //而是进行先搞一个新的指针变量,确定成功了,再进行赋值//也就是int* ptr = (int*)realloc(p, 10 * sizeof(int));if (ptr == NULL){perror("realloc:");//打印错误信息如果是空指针return 1;}p = ptr;for (int i = 0; i < 10; i++){*(p + i) = 0;printf("%d ", *(p + i));}free(p);p = NULL;return 0;
}

这里是15个0 

因为calloc也打印5个0 

不要误解

————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

malloc+free+calloc+realloc函数的综合使用

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{//malloc不初始化开辟空间//开辟20个字节的空间大小 int* p = (int*)malloc(20);if (p==NULL){perror("malloc:"); return 1;}//使用这20个字节的空间printf("malloc开辟空间的使用:");for (int i = 0; i < 5; i++){*(p + i) = i + 1;printf("%d ", *(p + i));}//释放开辟的空间free(p);//释放空间后不让p是野指针 指向空指针p = NULL;printf("\n\n\n");//calloc开辟初始化空间 //这里是开辟5个sizeof 整形大小的空间 也就是20个字节大小的空间 但是 这个空间的连续的int* s = (int*)calloc(5, sizeof(int));if (s == NULL){perror("calloc:");return 1;}printf("calloc开辟空间的使用:");for (int i = 0; i < 5; i++){printf("%d ", *(s + i));}//释放开辟的空间free(s);//释放空间后不让s是野指针 指向空指针s = NULL;printf("\n\n\n");//realloc调整空间大小//这里是开辟5个sizeof 整形大小的空间 也就是20个字节大小的空间 但是 这个空间的连续的int* a = (int*)calloc(5, sizeof(int));if (a == NULL){perror("calloc:");return 1;}printf("realloc的使用\ncalloc开辟空间的使用:");for (int i = 0; i < 5; i++){*(a + i) = i + 1;printf("%d ", *(a + i));}printf("\n");//调整空间大小,但是需要知道的是 空间调整大小的时候,容易导致丢失 所以我们首先检验一下 再进行赋值int* ptr = (int*)realloc(a, 40);if (ptr == NULL){perror("realloc:"); return 1;}a = ptr;//这里虽然是对于开辟空间的使用 但是实际上也是对于空间的覆盖for (int i = 0; i < 10; i++){*(a + i) = i + 5;printf("%d ", *(a + i));}free(a);a = NULL;return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js实现拖放效果

dataTransfer对象 说明&#xff1a;dataTransfer对象用于从被拖动元素向放置目标传递字符串数据。因为这个对象是 event 的属性&#xff0c;所以在拖放事件的事件处理程序外部无法访问 dataTransfer。在事件处理程序内部&#xff0c;可以使用这个对象的属性和方法实现拖放功能…

基于Java的校园疫情防控管理系统(Vue.js+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生2.2 老师2.3 学校管理部门 三、系统展示四、核心代码4.1 新增健康情况上报4.2 查询健康咨询4.3 新增离返校申请4.4 查询防疫物资4.5 查询防控宣传数据 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBoot…

element+Vue2,在一个页面跳转到另一个页面,并自动选中table的某一行

需求&#xff1a;点击A页面的某处&#xff0c;跳转到B页面并选中B页面表格的某一行&#xff08;点击B页面的搜索后需要清空默认选择的状态&#xff09;环境&#xff1a;vue2、element的table&#xff0c;table允许多选知识点&#xff1a;主要使用到table的这两属性&#xff1a;…

【每日跟读】常用英语500句(100~200)

【每日跟读】常用英语500句 My apologies. 我向你道歉 Mayday. 求救 I’m begging you. 我求你了 Allow me. 让我来 That’s for sure. 那是肯定的 I wish I could. 我希望我能 Don’t leave me. 别离开我 You suck. 你太烂了 In that case. 这样的话 From now on. 从…

【工具-MobaXterm】

MobaXterm ■ MobaXterm-简介■ MobaXterm-下载安装■ MobaXterm-(Session Settings)■ SSH■ Telnet■ Rsh (remote shell)■ Xdmcp■ RDP■ VNC (Virtual Network Console)■ FTP (文件传输)■ SFTP■ Serial■ File■ Shell■ Browser■ Mosh&#xff08;Mobile Shell)■ Aw…

前端web移动端学习day04

移动 Web 第四天 01-vw适配方案 vw和vh基本使用 vw和vh是相对单位&#xff0c;相对视口尺寸计算结果&#xff0c;相对于屏幕的逻辑参数 vw&#xff1a;viewport width&#xff08;1vw 1/100视口宽度 &#xff09;vh&#xff1a;lviewport height ( 1vh 1/100视口高度 ) …

Linux如何将桌面版转为mini版-解决中文字体变为英文字体

中文字体转为英文字体 我们进入Rocky-Linux后&#xff0c;ls或者打开文件夹发现有中文 我们执行命令 sudo localedef -i en_US -f UTF-8 en_US.UTF-8将其转为英文&#xff0c;并且重启机器 此时中文转化为英文 桌面版linux转为MINN版 1. 我们可以卸载桌面版 sudo dnf gr…

前端发版上线出现白屏问题

目录 路由配置问题资源缓存问题首屏加载过慢 &#xff1a;喂&#xff0c;你的页面白啦&#xff01; 出现上线白屏的问题有很多&#xff0c;如&#xff1a;配置错误、缓存问题、浏览器兼容问题&#xff0c;根据不同情况去解决。 路由配置问题 问题描述&#xff1a; 在vue开发…

【CSDN活动】程序员职业生涯的分水岭:年龄还是经验?

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 程序员职业生涯的分水岭&#xff1a;年龄还是经验&#xff1f;引言技术更新换代…

【Java程序设计】【C00377】基于(JavaWeb)Springboot的社区医疗服务系统(有论文)

【C00377】基于&#xff08;JavaWeb&#xff09;Springboot的社区医疗服务系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#x…

百人一岗,Android开发者的困境。。。。。

前言 在当前的Android开发领域&#xff0c;竞争的激烈程度已经达到了前所未有的水平&#xff0c;几乎到了100个开发者竞争1个岗位的地步。 这种“内卷”现象的背后&#xff0c;是技术的快速发展和市场对Android开发者技能要求的不断提升。随着移动应用的普及和多样化&#xf…

【c++】类和对象(四)深入了解拷贝构造函数

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好啊&#xff0c;本篇内容带大家深入了解拷贝构造函数 目录 1.拷贝构造函数1.1传值调用的无限调用1.2浅拷贝1.3深拷贝1.4深拷贝的实现 1.拷贝构造函数 拷贝构造函数是一种特殊的…