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的地址赋给p
	ptr = 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);
}

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


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

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

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

相关文章

新手养布偶猫如何选择猫主食冻干?K9、sc、希喂三个品牌推荐!

布偶猫是食肉动物&#xff0c;但由于肠胃脆弱敏感&#xff0c;所以在饮食上需要特别关注哦&#xff01;为了给它们最好的呵护&#xff0c;现在有了主食冻干这种优质猫主食&#xff01;它不仅符合猫咪的天然饮食习惯&#xff0c;还用了新鲜生肉做原料呢&#xff01;营养满分不说…

我的隐私计算学习——联邦学习(2)

笔记内容来自多本书籍、学术资料、白皮书及ChatGPT等工具&#xff0c;经由自己阅读后整理而成 &#xff08;三&#xff09;联邦学习的算子 ------------------------ 算子是什么&#xff1f;--------------------------- ​ 从广义上讲&#xff0c;对任何函数进行某一项操作都可…

设计模式学习2

代理模式&#xff1a;Proxy 动机 “增加一层间接层”是软件系统中对许多复杂问题的一种常见解决方案。在面向对象系统中&#xff0c;直接食用某些对象会带来很多问题&#xff0c;作为间接层的proxy对象便是解决这一问题的常见手段。 2.伪代码&#xff1a; class ISubject{ pu…

SPI知识大全

目录 SPI介绍SPI分为硬件SPI与软件SPISPI工作模式和时序图硬件SPI编写软件SPI编写拓展&#xff1a; SPI介绍 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种常用的通信接口&#xff0c;用于在两个设备之间进行数据传输。它通常用于板级通信&#xff0c;具有高…

SolidUI Gitee GVP

感谢Gitee&#xff0c;我是一个典型“吃软不吃硬”的人。奖励可以促使我进步&#xff0c;而批评往往不会得到我的重视。 我对开源有自己独特的视角&#xff0c;我只参与那些在我看来高于自身认知水平的项目。 这么多年来&#xff0c;我就像走台阶一样&#xff0c;一步一步参与…

Redis——centos7环境安装Redis6.2.14版本,make命令编译时报错:jemalloc/jemalloc.h:没有那个文件或目录

一、报错原因 在redis-6.2.14文件夹下有一个README.md文件&#xff0c;有如下一段话&#xff1a; 在构建 Redis 时&#xff0c;通过设置 MALLOC 环境变量来选择非默认的内存分配器。Redis 默认编译并链接到 libc malloc&#xff0c;但在 Linux 系统上&#xff0c;jemalloc 是…

AntV-G6 -- 将G6图表应用到项目中

1. 效果图 2. 安装依赖 npm install --save antv/g6 3. 代码 import { useEffect } from alipay/bigfish/react; import G6 from antv/g6;const data {id: root,label: 利息收入,subLabel: 3,283.456,ratio: 3,children: [{id: child-a,label: 平均利息,subLabel: 9%,ratio:…

【airsim】python控制airsim

使用airsim 1.8.1编译完成&#xff0c;进过block项目在cpp测试后&#xff0c;开始踩坑使用python。 使用AirSim\PythonClient\setup.py或者pip安装airsim。 python setup.py install或者 pip install airsim此时&#xff0c;windows电脑的环境信息 (air_py38) D:\code\Gith…

JDBC数据库访问——数据库操作

与指定的数据库建立连接后&#xff0c;就可以使用JDBC提供的API对数据库进行操作&#xff0c;包括查询、新增、更新、删除等。 1.查询操作 和数据库建立连接后&#xff0c;对数据库表进行查询操作的步骤如下&#xff1a; ①创建statement对象 由已创建的Connection对象con调…

PID各种算法的基本优缺点

PID时间系数对PID本身的影响 积分时间过小积分作用增强。 微分时间过大&#xff0c;微分控制作用过强&#xff0c;容易产生振荡。 在这里的时间系统&#xff0c;一般指的是采样的时间&#xff0c;也就是PID控制的周期。在无人机当中一般采用10ms控制一次。 一般来说采样周期越小…

【Docker】容器的相关命令

上一篇&#xff1a;创建&#xff0c;查看&#xff0c;进入容器 https://blog.csdn.net/m0_67930426/article/details/135430093?spm1001.2014.3001.5502 目录 1. 关闭容器 2.启动容器 3.删除容器 4.查看容器的信息 查看容器 1. 关闭容器 从图上来看&#xff0c;容器 aa…

如何在 Xftp 中使用自定义编辑器编辑远程服务器文件

1、简介 很多时候我们使用 Xshell 远程登录linux服务器进行文本编辑&#xff0c;通过命令行窗口难以进行快速编辑&#xff0c;因此&#xff0c;借助 Xftp 工具&#xff0c;指定文本编辑器&#xff0c;能够快速帮助我们实现文本编辑。 2、Xftp 使用 在上文中&#xff08;https:…

软件工程概论------文件管理

目录 1.文件的相关概念 2.文件目录 3.位示图 4.索引文件 5.例题 1.文件的相关概念 文件:具有符号名的、在逻辑上具有完整意义的一组相关信息项的集合。 逻辑结构:有结构的记录式文件、无结构的流式文件。 物理结构: 连续结构、链接结构、索引结构、多个物理块的索引表。 …

乔布斯在斯坦福大学经典演讲

今天&#xff0c;很荣幸来到各位从世界上最好的学校之一毕业的毕业典礼上。我从来没从大学毕业过&#xff0c;说实话&#xff0c;这是我离大学毕业最近的一刻。 今天&#xff0c;我只说三个故事&#xff0c;不谈大道理&#xff0c;三个故事就好。 第一个故事&#xff0c;是关于…

【ChatGPT】提示设计的艺术:使用清晰的语法

探索清晰的语法如何使您能够将意图传达给语言模型&#xff0c;并帮助确保输出易于解析 All images were generated by Scott and Marco. 这是与Marco Tulio Ribeiro共同撰写的关于如何使用指导来控制大型语言模型&#xff08;LLM&#xff09;的系列文章的第一部分。我们将从基…

Spring中的工厂类ApplicationContext和BeanFactory

1.ApplicationContext ApplicationContext的实现类&#xff0c;如下图 ClassPathXmlApplicationContext&#xff1a;加载类路径下 Spring 的配置文件 FileSystemXmlApplicationContext&#xff1a;加载本地磁盘下 Spring 的配置文件 ApplicationContext由BeanFactory派生而…

标签函数 - 打造JavaScript组件

&#x1f4e2; 鸿蒙专栏&#xff1a;想学鸿蒙的&#xff0c;冲 &#x1f4e2; C语言专栏&#xff1a;想学C语言的&#xff0c;冲 &#x1f4e2; VUE专栏&#xff1a;想学VUE的&#xff0c;冲这里 &#x1f4e2; CSS专栏&#xff1a;想学CSS的&#xff0c;冲这里 &#x1f4…

计算机基础知识——校验码概述

目录 1 码距 2 奇偶校验 3 CRC循环冗余校验码 3.1 多项式 3.2 编码的组成 3.3 生成多项式 3.4 校验码的生成 4 海明校验码和恒比码 4.1 校验方程 4.2 恒比码 1 码距 码距是恒量一种编码方式的抗错误能力的一个指标。数字信息在传输和存取的过程中&#xff0c;由于…

权威认可!甄知科技猪齿鱼产品荣获信创产品评估证书

近日&#xff0c;依据《信息技术应用创新产品评估规范 第1部分&#xff1a;应用软件》&#xff08;T/SSIA 2001-2022&#xff09;&#xff0c;经过严格评估&#xff0c;甄知科技旗下自主研发的猪齿鱼数智化开发管理平台 V2.0.0&#xff0c;通过信创测试认证&#xff0c;获得上海…

Jmeter相关知识介绍

Jmeter 是Apache 组织开发的基于JAVA 的压力测试工具,用于对软件做压力测试,特别适合于WEB 应用测试(包括压力,接口测试) 今天简单介绍Jemeter的入门相关概念的理解 一、在安装目录下有一个Bin\Jmeter.bat 双击打开 打开之后是一个这样的界面 二、测试计划 1、添加和删…