C语言之动态内存管理篇(1)

news2024/11/19 5:33:33

目录

为什么存在动态内存分配

动态内存函数的介绍

malloc

free

calloc

realloc

常见的动态内存错误


今天收假了,抓紧时间写几篇博客。我又来赶进度了。今天我们来讲解动态内存管理。🆗🆗

为什么存在动态内存分配

假设我们去实现一个通讯录,我们设置通讯录的大小是固定的100个元素,存放100个人的信息。如果信息太多,空间小了。如果信息太少,空间又大了。那我们应该怎样去解决?动态内存管理!

在目前为止,我们已经掌握两种向栈区申请内存的方式。

#include<stdio.h>
int main()
{
	int a = 10;//在栈空间申请四个字节存放一个值
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };//在栈空间开辟连续的空间存放一组数
	return 0;
}

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

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

但是对于空间的需求,不仅仅是上诉的情况。有时候我们需要的空间大小在程序运行的时候才能知道那数组的编译时开辟空间的方式就不能满足了。 这时候C语言给程序员一种权利【能够动态的申请和管理内存空间】就是【动态内存开辟】,当然除了在申请的同时 我们也要学会释放空间。

当然我们头脑中还是要有【内存分布图】

动态内存函数的介绍

 接下里我们分别给大家详细介绍一下动态内存开辟的函数 我们将从:头文件  函数参数 返回值 使用等方面去介绍。大家认真学起来!!

malloc

 malloc - C++ Reference (cplusplus.com)

  • 头文件 #include<stdlib.h>
  • 函数参数  size_t size
  • 函数参数表示开辟size个字节的空间大小,单位是字节
  • 如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。
  • 函数返回值是void *   
  • 如果开辟成功,则返回一个指向开辟好空间的指针
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
  • 返回值的类型是void* 是因为malloc函数并不知道开辟的空间类型,具体在使用的时候使用者自己来决定。
  • 当malloc在使用的时候,已经知道是开辟的空间是存放那种类型的数据了,可以强制类型转化
  • malloc函数是向内存申请一块连续可用的空间,并返回指向这块空间的指针。
  • malloc函数和free函数是配合使用的。
  • malloc函数申请的空间是需要释放的。 

 

 【malloc的使用需要注意:强制类型转化&&判断&&需要free释放】

//假设现在程序员A想申请40个字节的空间去存放10个整型
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));//强制类型转化
	//开始存放
	if (p == NULL)
	{
		perror("malloc");//为空的原因
		return 1;//非0即不能正常返回
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p[i] = 1+i;//p相当于数组名
		//p+i=i+1;
	}
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);//p+i
	}
	//释放
	free(p);
	p = NULL;
	return 0;//可以正常返回
}

忘记【perror库函数】戳一戳:C语言之字符函数&字符串函数篇(2)_唐唐思的博客-CSDN博客

 当然如果申请的空间太大,也是不可以的!

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
int main()
{
	int* p = (int*)malloc(INT_MAX*4);//强制类型转化
	                      //这里的空间过大会返回NULL的
	if (p == NULL)
	{
		perror("malloc");//为空的原因
		return 1;//非0即不能正常返回
	}
	return 0;
}

【malloc函数申请的空间是需要释放的】要怎么释放呢?

  • 主动释放:配合free函数使用。
  • 被动释放:程序退出之后,malloc函数申请的空间,就会被操作系统自动回收的。
  • 注意:正常情况下,谁申请的空间,谁去释放。即便不释放,也要告诉别人,让别人有机会去释放。🆗🆗很重要!

free

free - C++ Reference (cplusplus.com)

 

  • 头文件 #include<stdilb.h>
  • free函数参数是 void*ptr
  • 如果参数ptr指向的空间是动态开辟的,那么free会将其释放掉。
  • 如果参数ptr 指向的空间不是动态开辟,那free函数的行为是未定义的。
  • 如果参数ptr NULL指针,则函数什么事情也不做。
  • 函数没有返回值
  • free函数和malloc函数是配合使用的。
  • free函数专门是用来做动态内存的释放和回收的。
  • 特别提醒:free完了之后空间已经被释放了,p里面任然有地址,此刻p就变成了【野指针】,所以请把p赋值为NULL(空指针)
	free(p);
	p = NULL;//p是接收malloc开辟的空间的起始地址的指针变量
#include <stdio.h>
int main()
{
	//代码1
	int num = 0;
	scanf("%d", &num);
	int arr[num] = { 0 };
	//代码2
	int* ptr = NULL;
	ptr = (int*)malloc(num * sizeof(int));
	if (NULL != ptr)//判断ptr指针是否为空
	{
		int i = 0;
		for (i = 0; i < num; i++)
		{
			*(ptr + i) = 0;
		}
	}
	free(ptr);//释放ptr所指向的动态内存
	ptr = NULL;//是否有必要?
	return 0;
}

calloc

calloc - C++ Reference (cplusplus.com)  

  • 头文件 #include<stdlib.h>
  • 函数参数   size_t num size_t size (可以理解为将malloc的一个参数拆分为calloc的两个参数)
  • 参数num是元素个数
  • 参数size是一个元素的大小,单位是字节
  • 函数返回值是 void*
  • 如果开辟成功,则返回一个指向开辟好空间的指针
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
  • 返回值的类型是void* 是因为calloc函数并不知道开辟的空间类型,具体在使用的时候使用者自己来决定。
  • 当calloc在使用的时候,已经知道是开辟的空间是存放那种类型的数据了,可以强制类型转化
  • calloc函数也是用来动态内存分配的
  • calloc所申请的空间也需要free函数去释放
  • 函数的功能为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
  • 函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。
//向堆区申请10个整型的空间
calloc(10, sizeof(int));
malloc(10 * sizeof(int));

除了参数的区别,calloc函数申请好空间后【会将空间初始化为0】但是malloc函数不会初始化。 

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10,sizeof(int));//强制类型转化
	int* p = (int*)malloc(10*sizeof(int));//强制类型转化
	//开始存放
	if (p == NULL)
	{
		perror("malloc");//为空的原因
		return 1;//非0即不能正常返回
	}
	int i = 0;
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);//p+i
	}
	//释放
	free(p);
	p = NULL;
	return 0;//可以正常返回
}

malloc打印出来的是随机值,而calloc打印出来是初始化为0的值。 根据需求使用,如果需要初始化为0,那我们可以使用【calloc】,如果不需要初始化为0,我们可以使用【malloc】

realloc

有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。 realloc - C++ Reference (cplusplus.com)

  •  头文件 #include<stdlib.h>
  •  函数realloc的参数void* ptrptr是要调整的内存地址(内存的起始地址也就是原来malloc和calloc已经开辟的空间的起始地址p)
  •  函数realloc的参数size_t sizesize调整之后新大小(调整新的大小需要多少),单位是字节
  •  参数size不是指新增加或减少的差距❌
  •  函数返回值是void *类型
  •  返回值为调整之后的内存起始位置
  •  返回值的类型是void* 是因为realloc函数并不知道开辟的空间类型,具体在使用的时候使用者   自己来决定。
  • 如果开辟成功,则返回一个指向开辟好空间的指针
  • 指向开辟好的空间的指针变量(分情况讨论) 

1.可能与旧空间的起始地址一致  2.可能是一块全新的空间的起始地址

 

  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
  •  realloc函数是对已经通过malloc和calloc函数开辟过的空间进行调整
  •  realloc函数的出现就是为了让动态内存管理更加灵活
  •  realloc函数在调整内存空间的是存在两种情况:
  1. 情况一:原有空间之后有足够大的空间。
  2. 情况二:原有空间之后没有足够大的空间。
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。

关于realloc函数有返回值来接收有三种不同写法。

【写法1】


p = realloc(p, 20 * sizeof(int));//用旧空间的原来的指针变量去接收(NULL问题) 

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10,sizeof(int));//强制类型转化
	//开始存放
	if (p == NULL)
	{
		perror("malloc");//为空的原因
		return 1;//非0即不能正常返回
	}
	int i = 0;
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	//空间不够,希望调整空间为20个整型的空间
	p = realloc(p, 20 * sizeof(int));
	//不建议这样写  可能开辟空间失败返回NULL
	// 成功也就罢了,万一失败旧空间起始地址也找不到了
	//释放
	free(p);
	p = NULL;
	return 0;//可以正常返回
}

【写法2】


int* ptr = (int*)realloc(p, 20 * sizeof(int));//用新的指针变量去接收,但记住一定要释放 

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10,sizeof(int));//强制类型转化
	//开始存放
	if (p == NULL)
	{
		perror("malloc");//为空的原因
		return 1;//非0即不能正常返回
	}
	int i = 0;
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	//空间不够,希望调整空间为20个整型的空间
	int *ptr = (int*)realloc(p, 20 * sizeof(int));//换一个指针变量去管理
	//如果你就是使用ptr,一定记得要释放ptr所指向的空间
	//释放
	free(p);
    free(ptr);
	p = NULL;
    ptr=NULL;
	return 0;//可以正常返回
}

【写法3】


int* ptr = (int*)realloc(p, 20 * sizeof(int));

if (ptr != NULL)
{
    p = ptr;
}

 

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)calloc(10,sizeof(int));//强制类型转化
	//开始存放
	if (p == NULL)
	{
		perror("malloc");//为空的原因
		return 1;//非0即不能正常返回
	}
	int i = 0;
	//打印
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	//空间不够,希望调整空间为20个整型的空间
	int *ptr = (int*)realloc(p, 20 * sizeof(int));
	//但是,程序员还是想要p来管理这块空间,可以这么写
	if (ptr != NULL)
	{
		p = ptr;
	}
	//释放
	free(p);
	p = NULL;
	return 0;//可以正常返回
}

关于就是realloc函数返回的指针的两种不同的情况。 

【情况1 】


要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

  • realloc函数此时的返回值是旧的空间的起始地址 

​ 

【情况2】 


原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。 且realloc函数有三个特点

  • realloc函数会将旧的空间的数据,拷贝到新的空间里
  • realloc函数拷贝完成后,会将旧的空间释放掉
  • realloc函数此刻的返回值不是原来的地址,而是新的空间的起始地址

​ 

当然除此之外,realloc还可以当成malloc来使用,只要传空指针即可。

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* ptr = (int*)realloc(NULL, 10 * sizeof(int));
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	free(ptr);
	ptr = NULL;
	return 0;
}

常见的动态内存错误

  • 对NULL指针的解引用操作
  • 对动态开辟空间的越界访问
  • 对非动态开辟内存使用free释放
  • 使用free释放一块动态开辟内存的一部分
  • 对同一块动态内存多次释放
  • 动态开辟内存忘记释放(内存泄漏)

动态开辟的空间一定要正确释放!!

✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!下篇博文我们讲解几道相关笔试题

代码------→【gitee:唐棣棣 (TSQXG) - Gitee.com】

联系------→【邮箱:2784139418@qq.com】

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

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

相关文章

Iris for Mac:轻松实现高质量录屏的最佳选择

随着数字化时代的到来&#xff0c;录屏软件已经成为了许多人必备的工具之一。无论是教育、工作还是娱乐&#xff0c;录屏软件都可以帮助我们将重要的操作过程或内容记录下来&#xff0c;并与他人分享。而对于Mac用户来说&#xff0c;一款简单易用且功能强大的录屏软件尤为重要。…

划片机:半导体生产的必备设备

划片机是半导体加工行业中的重要设备&#xff0c;主要用于将晶圆切割成晶片颗粒&#xff0c;为后道工序粘片做好准备。随着国内半导体生产能力的提高&#xff0c;划片机市场的需求也在逐渐增加。 在市场定位上&#xff0c;划片机可以应用于半导体芯片和其他微电子器件的制造过程…

015 Spring Boot网上商城(仿天猫)

一、系统介绍 需求设计主要参考天猫商城的购物流程&#xff1a; 用户从注册开始&#xff0c;到完成登录&#xff0c;浏览商品&#xff0c;加入购物车&#xff0c;进行下单&#xff0c;确认收货&#xff0c;评价等一系列操作。 作为迷你天猫商城的核心组成部分之一&#xff0…

为什么公司里月薪八千的PLC工程师经常离职?

今日话题&#xff0c;为什么公司里月薪八千的PLC工程师经常离职&#xff1f;这个问题涉及到工程师的个人偏好和工作性质的不同。许多工程师更喜欢在一个稳定的地方工作&#xff0c;而不是经常出差。然而&#xff0c;也有一些工程师喜欢出差&#xff0c;他们更愿意在不同的现场工…

PMP认证,对项目经理有什么用?

PMP是什么&#xff1f;学什么&#xff1f; PMP是由美国项目管理协会&#xff08;PMI&#xff09;在全球范围内推出的针对项目经理的资格认证体系&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试&#xff0c;其目的是为了给项目管理人员提供统一的行业标…

【Python_PySide2学习笔记(十七)】QPlainTextEdit末尾增加文本时设置文本颜色

QPlainTextEdit末尾增加文本时设置文本颜色 前言正文1、QPlainTextEdit末尾增加文本时设置文本颜色方法2、f_changeQPlainTextEditColor()方法调用前言 此篇文章中介绍PySide2中 QPlainTextEdit 多行文本框在末尾增加文本的同时设置文本颜色的方法,而对插入的文本进行区分,有…

设计模式13、模版方法模式 Template Method

解释说明&#xff1a;模版方法模式&#xff08;Template Method Pattern&#xff09;定义一个操作中算法的骨架&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤 抽象类&#xff08;AbstractClass&#xff09;&…

二分查找 红蓝染色法 【基础算法精讲 04】

视频链接 : 二分查找 红蓝染色法_哔哩哔哩_bilibili 在排序数组中查找元素的第一个和最后一个位置 链接 : 在排序数组中查找元素的第一个和最后一个位置 思想 : 暴力 : 在lc上&#xff0c;直接暴力枚举左端点和右端点也是能够通过的! 二分 : 题目要求在O(log n)的时…

ToBeWritten之威胁狩猎环境应用

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

放弃36年的鞋服业务转而“卖粮”,贵人鸟胜算几何?

正处“中年”的运动鞋服老品牌贵人鸟&#xff0c;却开始了一场大转型。 近日&#xff0c;贵人鸟发布了优化调整公司经营业务的公告。公告提到&#xff0c;公司将逐步退出运动鞋服业务&#xff0c;聚焦粮食贸易。 回顾来看&#xff0c;贵人鸟曾在运动鞋服领域颇受市场认可。据了…

千兆光模块和万兆光模块已经过时了吗?

千兆和万兆光模块在过去很长一段时间里是网络交换机和路由器的核心所在&#xff0c;它们基于光纤传输技术&#xff0c;具有高速、稳定、效率高的特点。随着数字时代的来临&#xff0c;网络端也催生了更大带宽需求&#xff0c;这无疑对光模块的性能提出了更高的要求。我们不得不…

vue3富文本编辑器的二次封装开发-Tinymce

欢迎点击领取 -《前端面试题进阶指南》&#xff1a;前端登顶之巅-最全面的前端知识点梳理总结 *分享一个使用比较久的&#x1fa9c; 简介 1、安装&#xff1a;pnpm add tinymce / pnpm add tinymce/tinymce-vue > Vue3 tinymce tinymce/tinymce-vue 2、功能实现图片上传…

分布式锁:5种方案解决商品超卖的方案

一 分布式锁 1.1 分布式锁的作用 在多线程高并发场景下&#xff0c;为了保证资源的线程安全问题&#xff0c;jdk为我们提供了synchronized关键字和ReentrantLock可重入锁&#xff0c;但是它们只能保证一个工程内的线程安全。在分布式集群、微服务、云原生横行的当下&#xff…

w10系统 如何使用 C++、cmake、opencv、

w10系统的C环境配置 1.安装 vscode编辑器 首先安装&#xff1a;VScode 安装后开始安装插件&#xff1a; C 插件 2.配置w10系统的C环境 使用编译器MinGW 官方地址&#xff1a;https://www.mingw-w64.org/ 下载地址&#xff1a;https://sourceforge.net/projects/mingw-w64/f…

AI产品经理-能力模型

一、概况 AI产品经理/助理&#xff08;需求工程师&#xff09;&#xff1a;大多数入门的AI产品经理应该都在这里&#xff0c;顾名思义&#xff0c;就是在整体产品规划中帮助大PD实现部分产品功能的助理或者需求工程师&#xff0c;需要具备比较强的AI知识框架与理解能力以保障各…

Openlayers 教程 - 地图以及图层数据导出(打印)图片

Openlayers 教程 - 地图以及图层数据导出&#xff08;打印&#xff09;图片 地图导出核心代码完整代码&#xff1a;在线示例 本文包括地图导出核心代码、完整代码以及在线示例。 地图导出核心代码 这里放上 ES 封装的核心代码&#xff0c;创建多边形或者其他几何对象&#xff…

做小说推文和短剧推广,找数据好的授权平台

小说推文和短剧推广很多平台吃单怎么办&#xff1f;可以试试”巨量推文“&#xff0c;一个不吃单的平台 众所周知 小说推文和短剧推广很多平台会吃单&#xff0c;比如你实际官方数据是10个订单&#xff0c;很多平台只给你5个&#xff0c;这样你损失可能就是一半的利润&#xf…

【MySQL】基本查询(二)

文章目录 一. 结果排序二. 筛选分页结果三. Update四. Delete五. 截断表六. 插入查询结果结束语 操作如下表 //创建表结构 mysql> create table exam_result(-> id int unsigned primary key auto_increment,-> name varchar(20) not null comment 同学姓名,-> chi…

虚拟展厅有什么重要意义,了解虚拟展厅在宣传中的应用

引言&#xff1a; 随着科技的不断进步&#xff0c;虚拟展厅已经逐渐成为展览行业的重要一环。虚拟展厅是一种数字化平台&#xff0c;为观众提供了与传统展览完全不同的体验。 一&#xff0e;虚拟展厅的定义 虚拟展厅是一个通过互联网和虚拟现实技术创建的数字展示空间&#x…

windows系统下利用python对指定文件夹下面的所有文件的创建时间进行修改

windows系统下利用python对指定文件夹下面的所有文件的创建时间进行修改 不知道其他的朋友们有没有这个需求哈&#xff0c;反正咱家是有这个需求 需求1、当前有大量的文件需要更改文件生成的时间&#xff0c;因为不可告知的原因&#xff0c;当前的文件创建时间是不能满足使用的…