当前位置: 首页 > news >正文

C语言中灵活多变的动态内存,malloc函数 free函数 calloc函数 realloc函数

请添加图片描述

文章目录

  • 🚀前言
  • 🚀管理动态内存的函数
    • ✈️malloc函数
    • ✈️free函数
    • ✈️calloc函数
    • ✈️realloc函数
  • 🚀在使用动态内存函数时的常见错误
    • ✈️对NULL指针的解引用
    • ✈️ 对动态开辟空间的越界访问
    • ✈️对非动态开辟内存使用free释放
    • ✈️使用free释放一块动态开辟内存的一部分
    • ✈️对同一块动态内存多次释放
    • ✈️动态开辟内存忘记释放(内存泄漏)

🚀前言

铁子们好啊!今天阿辉给大家讲一下C语言里面特别重要的一块知识——动态内存管理,为什么说它重要呢?相信大家在使用数组时都遇到过数字开辟空间太大或者太小的情况,这是很尴尬的因为数组空间一旦确定就难以扩大或者缩小。而今天的动态内存管理将帮我们很好的解决这一窘境。话不多说,开始咱们今天的学习吧!!!

🚀管理动态内存的函数

动态内存的管理其实也就分为两块

  • 空间的开辟和扩容
  • 空间的释放

而要做到以上两点,我们要引入几个重要的管理动态内存的函数

动态内存的开辟和释放都是在堆区上

✈️malloc函数

malloc函数是用来开辟空间的,如何使用呢?下面是它的声明👇

void* malloc(size_t size);

关于malloc函数的注意事项:

  • size表示malloc函数所开辟空间的大小,单位是字节
  • maloc函数对于开辟空间存放何种类型的数据并不关心,返回值是void*类型,malloc开辟空间成功,则返回这块空间的起始位置的地址;若开辟空间失败,则返回空指针NULL
  • malloc传入的参数为0时,这种行为是C语言标准未定义的,取决于编译器
  • malloc函数开辟的空间,里面的内容是随机的

具体使用:

int mian()
{int* p = (int*)malloc(sizeof(int) * 10);//开辟10*4个字节的空间,返回值强转为int*if (p == NULL)//判断动态内存是否开辟成功{printf("malloc 开辟空间失败\n");//开辟失败返回调试语句,就是让程序员知道哪错了return 1;//开辟失败直接返回}//对动态开辟内存的进一步使用//这玩意其实就是个数组,有了首元素地址,不就是当成数组来玩嘛for (int i = 0; i < 10; i++)//十个元素初始化成0~9{p[i] = i;//这玩意与*(p+i) = i等价,不懂得可以看阿辉之前关于指针的文章}return 0;
}

关于malloc函数开辟的空间,它是一块连续的空间,直接当成数组使用一点毛病没有,
它与数组最大的区别在于,malloc开辟的空间是在堆区上的,而数组是在栈区上的。
而堆区上申请的空间须有程序员自己手动释放(Java,Python有垃圾回收机制),否则将造成内存泄漏。其实就是你从我这拿了空间去用,不用了就还给我,别占着茅坑不拉屎,你不用别人也用不了。对于堆区申请的空间的释放,这里要引入下面这个新的函数

✈️free函数

C语言提供了一个函数free,专门用来做动态内存的释放和回收的,函数声明如下:

void free(void* ptr);

对于free函数使用时的注意事项:

  • 对于传给free的参数必须是指向动态开辟内存(也就是是堆区开辟的空间)的起始地址的指针
  • 若传给free的参数是空指针NULLfree函数则什么也不干
  • free只会释放传入的指针指向的空间,并不会给传入指针置空,这会很危险,空间你都还给操作系统了,你这个指针还指向那里,这个指针很野得治,所以free完,指针我们要置空
int mian()
{//开辟动态空间int* p = (int*)malloc(sizeof(int) * 10);//判断动态内存是否开辟成功if (p == NULL){printf("malloc 开辟空间失败\n");return 1;}/*对动态开辟空间的使用*///不用啦,释放空间free(p);p = NULL;return 0;
}

👆这段代码就是动态内存的使用的基本模式,先开辟空间,然后判断是否开辟成功,接着使用这块空间,最后不用了把这块空间释放掉

✈️calloc函数

C语言中还提供了calloc函数,同样是进行动态内存分配的,函数声明如下:

void* calloc(size_t num, size_t size);

callocmalloc仅有两点不同

  • 使用上calloc函数需要两个参数,开辟空间为num个大小为size个字节的空间
  • calloc函数开辟的空间会把每个字节全部初始化为0
int main()
{int* p = (int*)calloc(10, sizeof(int));if (p == NULL)//判断空间是否开辟成功{printf("calloc开辟空间失败\n");return 1;}for (int i = 0; i < 10; i++)//打印动态内存中的元素{printf("%d ", p[i]);}free(p);//空间释放p = NULL;//指针置空return 0;
}

输出:

0 0 0 0 0 0 0 0 0 0  //十个0

✈️realloc函数

铁子们估计有点不买账了,说好的动态内存分配,讲了这么多也没有体现动态俩字。铁子们别急,realloc函数才是今天的重头戏
C语言提供realloc函数用来使动态内存的使用更加灵活,之前开辟的空间太大或者太小都可以灵活的调整重新分配空间大小
realloc函数的函数声明

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

realloc函数在使用时要注意下面这几点:

  • ptr是要调整的空间的起始地址,ptr得是动态内存开辟的地址,若是ptr为空指针,realloc函数将与malloc函数的实现一样

  • sizerealloc函数调整大小后的内存空间大小

  • realloc函数的返回值是空间调整后的起始地址,空间开辟失败返回空指针

  • realloc函数扩容的空间里面的值并未被初始化,是随机值

  • 这个函数在调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间

  • 对于realloc函数调整空间有了两种情况:

    • 情况一:原有空间后有足够空间
      请添加图片描述

    • 情况二:原有空间后无足够空间,原有空间将被释放掉,重新找一块空间
      请添加图片描述

例子:

int main()
{int* p = (int*)malloc(5 * sizeof(int));//先用malloc申请5个整型大小的内存空间if (p == NULL)//判断是否开辟成功{printf("malloc开辟空间失败\n");return 1;}int i = 0;for (i = 0; i < 5; i++){*(p + i) = 1;//把5个整型全部初始化为1}//不够用了,要再增加5个整型int* ptr = (int*)realloc(p, 10 * sizeof(int));if (ptr == NULL){printf("realloc开辟空间失败\n");return 1;}p = ptr;//空间扩容成功将ptr的地址赋给pptr = NULL;//ptr置空for (i = 0; i < 10; i++){printf("%d ", *(p + i));}free(p);p = NULL;return 0;
}

上述,使用realloc对空间做调整时,一定要新创建一个变量来接收realloc的返回值,因为如果使用指向原空间的起始地址的指针p来接收,一旦realloc开辟空间失败,p将被赋值成NULL,将找不到原来空间造成内存泄漏

🚀在使用动态内存函数时的常见错误

✈️对NULL指针的解引用

void test()
{int* p = (int*)malloc(INT_MAX / 4);*p = 20;//如果p的值是NULL,就会有问题free(p);
}

✈️ 对动态开辟空间的越界访问

void test()
{int i = 0;int* p = (int*)malloc(10 * sizeof(int));if (NULL == p){exit(EXIT_FAILURE);}for (i = 0; i <= 10; i++){*(p + i) = i;//当i是10的时候越界访问}free(p);
}

✈️对非动态开辟内存使用free释放

void test()
{int a = 10;int *p = &a;free(p);//error——不能对非动态内存进行释放
}

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

void test()
{int *p = (int *)malloc(100);p++;free(p);//p不再指向动态内存的起始位置
}

✈️对同一块动态内存多次释放

void test()
{int *p = (int *)malloc(100);free(p);free(p);//重复释放
}

✈️动态开辟内存忘记释放(内存泄漏)

void test()
{int *p = (int *)malloc(100);if(NULL != p){*p = 20;}
}
int main()
{test();while(1);
}

对于动态开辟的内存一定要记得释放,否则将造成内存泄漏


如果觉得文章对你有帮助的话,还请点赞,关注,收藏支持博主,如有不足还请指点,博主及时改正,感谢大家支持!!!
请添加图片描述

相关文章:

C语言中灵活多变的动态内存,malloc函数 free函数 calloc函数 realloc函数

文章目录 &#x1f680;前言&#x1f680;管理动态内存的函数✈️malloc函数✈️free函数✈️calloc函数✈️realloc函数 &#x1f680;在使用动态内存函数时的常见错误✈️对NULL指针的解引用✈️ 对动态开辟空间的越界访问✈️对非动态开辟内存使用free释放✈️使用free释放一…...

小细节处理

重载运算符&#xff1a;重载<运算符。 bool operator<(const Edge&s)const{return w<s.w;}...

【42页动态规划学习笔记分享】动态规划核心原理详解及27道LeetCode相关经典题目汇总

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐--…...

Python正则的匹配与替换

import re 查找时的注意事项&#xff0c;要查找的内容左右两边打出来&#xff0c;用真正的字符&#xff0c;不要用.*?&#xff0c;离查找内容远一点&#xff0c;再用.*? a /aksj<a>哈哈哈<a><p>拉阿鲁<p>\.askjp b re.findall(<a>(.*?)<…...

解决ELement-UI懒加载三级联动数据不回显(天坑)

最老是遇到这类问题头有点大,最后也是解决了,为铁铁们总结了一下几点 一.查看数据类型是否一致 未选择下 选择下 二.处理数据时使用this.$set方法来动态地设置实例中的属性&#xff0c;以确保其响应式 三.绑定v-if 确保每次重新加载 四.绑定key 五.完整代码...

【数据结构和算法】找出两数组的不同

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 哈希类算法题注意事项 2.2 方法一&#xff1a;哈希法 三、代码 3.1 方法一&#xff1a;哈希法 四…...

基于Python的B站排行榜大数据分析与可视化系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 本文介绍了一项基于Python的B站排行榜大数据分析与可视化系统的研究。通过网络爬虫技术&#xff0c;系统能够自动分析B站网址&#xff0c;提取大量相关文本信息并存储在系统中。通过对这些信息进行…...

MySQL一些常用命令

1、登录本地MySQL #一种是 mysql -u root -p; #(输入密码后回车)#另一种是 mysql -uroot -p123456; #(在-p后面直接带上密码)2、启动MySQL服务 net start mysql; 3、关闭MySQL服务&#xff1a; net stop mysql; 4、创建数据库 create database 数据库名; 5、创建数据…...

WPF 新手指引弹窗

新手指引弹窗介绍 我们在第一次使用某个软件时&#xff0c;通常会有一个“新手指引”教学引导。WPF实现“新手指引”非常方便&#xff0c;且非常有趣。接下来我们就开始制作一个简单的”新手指引”(代码简单易懂&#xff0c;便于移植)&#xff0c;引用到我们的项目中又可添加一…...

py注册登录界面

代码分析 引入tkinter库&#xff0c;并从中导入messagebox模块。 read_users()函数用于读取存储用户信息的文本文件"users.txt"。它打开文件并逐行读取&#xff0c;将每行的用户名和密码以空格分隔后存储在一个列表中&#xff0c;最后返回该列表。 login(username,…...

基于电商场景的高并发RocketMQ实战-Consumer端队列负载均衡分配机制、并发消费以及消费进度提交

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 【11来了】文章导读地址&#xff1a;点击查看文章导读&#xff01; &#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f341;&#x1f3…...

【Java开发岗面试】八股文—数据库MySQLRedis

声明&#xff1a; 背景&#xff1a;本人为24届双非硕校招生&#xff0c;已经完整经历了一次秋招&#xff0c;拿到了三个offer。本专题旨在分享自己的一些Java开发岗面试经验&#xff08;主要是校招&#xff09;&#xff0c;包括我自己总结的八股文、算法、项目介绍、HR面和面试…...

IntelliJ IDEA [设置] 隐藏 .idea 等 .XXX 文件夹

文章目录 1. 问题描述2. 解决办法3. 最后效果4. 特殊处理&#xff08;正常不需要此步骤&#xff09;总结 我们使用 IntelliJ IDEA 导入项目的时候&#xff0c;经常会看到一些 .XXX 的文件夹&#xff08;例如&#xff1a;.idea&#xff0c;.mvn&#xff0c;.gradle 等&#xff0…...

每日一题——LeetCode961

方法一 排序法&#xff1a; 2*n长度的数组里面有一个元素重复了n次&#xff0c;那么将数组排序&#xff0c;求出排序后数组的中间值&#xff08;因为长度是偶数&#xff0c;没有刚好的中间值&#xff0c;默认求的中间值是偏左边的那个&#xff09;那么共有三种情况&#xff1a;…...

基于Unity Editor开发一个技能编辑器可能涉及到的内容

基于Unity Editor开发一个技能编辑器&#xff0c;涉及到的方面较多&#xff0c;涵盖了Unity自身的GUI框架、序列化系统、自定义编辑器、脚本调用与数据存储等。下面是几个关键点和你可能会用到的类以及API&#xff1a; 自定义Inspector&#xff1a; 使用Editor类来重写组件的I…...

Ubuntu 22.04 安装ftp实现与windows文件互传

Ubuntu 22.04 安装ftp实现与windows文件互传 1、配置安装 安装&#xff1a; sudo apt install vsftpd -y使能开机自启&#xff1a; sudo systemctl enable vsftpd 启动&#xff1a; sudo systemctl start vsftpd创建ftp工作目录&#xff1a; sudo mkdir -p /home/ftp/uftp…...

EasyPoi使用案例

EasyPoi使用案例 easypoi旨在简化Excel和Word的操作。基于注解的导入导出&#xff0c;修改注解就可以修改Excel&#xff1b;支持常用的样式自定义&#xff1b;基于map可以灵活定义表头字段&#xff1b;支持一对多的导入导出&#xff1b;支持模板的导出&#xff1b;支持HTML/Exc…...

分布式系统架构设计之分布式数据存储的分类和组合策略

在现下科技发展迅猛的背景下&#xff0c;分布式系统已经成为许多大规模应用和服务的基础架构。分布式架构的设计不仅仅是一项技术挑战&#xff0c;更是对数据存储、管理和处理能力的严峻考验。随着云原生、大数据、人工智能等技术的崛起&#xff0c;分布式系统对于数据的高效存…...

javaEE -18(11000字 JavaScript入门 - 3)

一&#xff1a;事件 &#xff08;高级&#xff09; 1.1 注册事件&#xff08;绑定事件&#xff09; 给元素添加事件&#xff0c;称为注册事件或者绑定事件&#xff0c;注册事件有两种方式&#xff1a;传统方式和方法监听注册方式 传统注册方式 &#xff1a; 利用 on 开头的…...

LangChain.js 实战系列:入门介绍

&#x1f4dd; LangChain.js 是一个快速开发大模型应用的框架&#xff0c;它提供了一系列强大的功能和工具&#xff0c;使得开发者能够更加高效地构建复杂的应用程序。LangChain.js 实战系列文章将介绍在实际项目中使用 LangChain.js 时的一些方法和技巧。 LangChain.js 是一个…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...