第五十三天学习记录:C语言进阶:动态内存管理Ⅰ

这篇具有很好参考价值的文章主要介绍了第五十三天学习记录:C语言进阶:动态内存管理Ⅰ。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问:
栈区堆区静态区的大小是固定的吗?如果栈区满了,会向后2者借位置吗?
ChatAI答:
栈区、堆区和静态区的大小通常是由操作系统或编译器预定义的,不是固定的。这些区域的大小通常受到多种因素的影响,如系统物理内存大小、进程虚拟地址空间的大小、编译器和操作系统的实现等等。

当栈区满了时,是不能向堆区或静态区借位置的。栈区和堆区是两个独立的内存区域,它们使用不同的指针来管理内存空间。当栈区满了,意味着当前栈帧中的内存空间已经全部使用完毕,如果需要分配更多的内存,需要在栈上创建一个新的栈帧来继续分配内存。但是,由于栈区的大小通常是有限的,当创建的栈帧数量过多或栈帧过大时,就会出现栈溢出的情况,导致程序崩溃。

另一方面,堆区和静态区可以被程序共享使用,甚至可以跨越多个栈帧和函数调用。堆区由malloc、realloc、calloc等函数动态分配,当内存不够时,它可以通过请求更多的虚拟内存来扩展堆区的大小。静态区的大小在编译时就已经确定,通常包括全局变量、静态变量、常量等,而且静态区的大小不会随着程序运行而改变。

总的来说,栈区、堆区和静态区的大小通常是由各种因素共同决定的,并不是固定的。程序在运行时会预先将这些区域划分好,而当其中的某个区域已经满了时,就需要通过不同的方式来处理。

动态函数的介绍

malloc和free
C语言提供了一个动态内存开辟的函数:

void* malloc (size_t size); 

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
。如果开辟成功,则返回一个指向开辟好空间的指针。
。如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
。返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
。如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

int main()
{
	//向内存申请10个整型的空间
	int* p = (int*)malloc(10 * sizeof(int));
	//int* p = (int*)malloc(INT_MAX);
	if (p == NULL)
	{
		//打印错误原因的一个方式
		printf("%s\n", strerror(errno));
	}
	else
	{
		//正常使用空间
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	free(p);
	p = NULL;
	return 0;
}

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

void free(void* ptr);

free函数用来释放动态开辟的内存。
。如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定位的。
。如果参数ptr是NULL指针,则函数什么事都不做。

calloc
C语言还提供了一个函数叫calloc,calloc函数也用来动态内存分配。原型如下:
void* calloc(size_t num,size_t size);
。函数的功能为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。
。与函数malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0.

问:
有calloc函数了还要malloc函数做什么?
ChatAI答:
calloc函数与malloc函数都是用来动态分配内存的函数,二者的不同之处在于内存分配和初始化的方式不同。

  • malloc函数分配内存空间时,内存中的数据不会被初始化,需要手动初始化才能使用。如果不进行初始化操作,申请的内存空间中可能残留着之前的垃圾数据,这就会对程序产生潜在的安全隐患。
  • 而calloc函数分配内存空间时,不仅会申请指定大小的内存,还会将其初始化为0。

因此,如果程序需要申请一块内存,并且希望该内存全部清零,那么就应该使用calloc函数;如果程序需要申请一块内存,但不需要初始化其中的数据,则需要使用malloc函数。

注意,calloc函数与malloc函数的返回值是相同的,它们都返回指向所分配内存的首字节的指针。需要注意的是,在使用calloc函数分配内存时,分配的空间大小第一个参数n和第二个参数size是传入的字节数的形式,例如calloc(n, size)中所请求的内存大小为 n*size 个字节。

总之,malloc函数和calloc函数都有各自的使用场景,根据实际情况选择使用。在申请内存时,应该根据需要进行初始化或者清零操作,确保程序的正确性和安全性。

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main()
{
	int * p = (int*)calloc(10 , sizeof(int));
	if (p == NULL)
	{
		//打印错误原因的一个方式
		printf("%s\n", strerror(errno));
	}
	else
	{
		//正常使用空间
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	free(p);
	p = NULL;
	return 0;
}

问:
如果malloc后又realloc将动态内存空间设置小了,再free,那么之前被改小的部分是在realloc的时候就释放了,还是要直到free的时候才释放?

ChatAI答:
如果使用realloc函数将先前申请的动态内存空间设置为比原先更小的大小,那么被裁剪的那一部分内存空间会立即被释放,即在realloc函数调用之后就被释放了。程序无法再访问被裁剪的那一部分内存空间,但是其内存空间并没有马上被OS收回,而是被保留在堆上,等待以后可能的内存分配请求。

当使用free函数释放指针所指的内存块时,其行为就与动态分配内存的方式是无关的。而是由malloc,calloc,realloc之类的函数所使用的堆管理器,根据内部的算法来决定如何回收内存块。因此,即使调用realloc函数将先前申请的内存缩小,被裁剪的那一部分内存空间也可能不会立即被OS收回,而可能暂时被保留在堆上,等待可能的内存分配请求。

在实际使用中,为了避免内存泄漏,建议在不需要使用先前申请的动态内存时,立即使用free函数将其释放,而不是让其保留在堆上。因此,如果在realloc函数之后又立即使用free函数释放指针所指的内存块,则被裁剪的那一部分内存空间应该能被立即回收,而不必等到程序结束或操作系统重启等时机。

realloc
realloc函数的出现让动态内存管理更加灵活。
为了合理的内存,我们会一定程度对内存的大小做灵活的调整。realloc函数可以做到对动态开辟内存大小的调整。函数原型如下:

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

。ptr是要调整的内存地址
。size调整之后新大小
。返回值为调整之后的内存起始位置
。这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间
。realloc在调整内存空间的是存在两种情况:
。情况1:原有空间之后有足够大的空间

问:realloc函数调整后返回的指针地址和先前malloc开辟返回的地址会不会发生改变?
ChatAI答:
realloc函数的作用是调整先前通过malloc或calloc函数动态分配的内存块的大小,并返回指向调整后内存块的新地址的指针。当内存块当前的大小不足以满足分配新内存时,realloc函数则会在其他地方重新申请新的内存块,并将先前内存块的数据复制到新的地址中,最后释放原先的内存块。这样做可以保证分配的新内存块的大小不会小于要求的大小,并且可以尽量减少内存的碎片。

如果调用realloc函数会导致内存大小实际上并没有发生变化,那么realloc函数就可能返回与先前内存块相同的地址。但是,调用realloc函数重新调整内存块大小时,返回的指针地址可能会发生改变。具体来说,如果realloc函数需要在其他地方重新申请内存块,则返回的指针地址将是新内存块的首地址;如果内存块可以直接调整大小,则返回的指针地址可能与先前的地址相同,但是不能保证这种情况始终发生。

因此,为了保险起见,在使用realloc函数时应该始终将其返回的指针赋值给一个新的指针变量,并且在使用完毕后,应该使用新指针变量来访问内存块,而不是依赖先前的指针变量。这样可以避免内存访问错误和其它潜在的问题,并提高程序的可靠性和稳定性。文章来源地址https://www.toymoban.com/news/detail-459402.html

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main()
{
	int * p = (int*)malloc(20);
	if (p == NULL)
	{
		//打印错误原因的一个方式
		printf("%s\n", strerror(errno));
	}
	else
	{
		//正常使用空间
		int i = 0;
		for (i = 0; i < 5; i++)
		{
			*(p + i) = 3 * i;
		}
		for (i = 0; i < 5; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	printf("\n");
	//realloc使用的注意事项:
	//1.如果p指向的空间之后有足够的内存空间可以追加,则直接追加,后返回p
	//2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一个新的内存区域
	//开辟一块满足需求的空间,并且把原来内存中的数据拷贝回来,释放旧的内存空间,最后返回新开辟
	//的内存空间的地址
	//3.得用一个新的变量来接收realloc函数的返回值(一般情况没什么,但若realloc申请失败返回了NULL,
	//就会把原指针给改成NULL,这样原来的内存也找不到了。)
	int* p2 = (int*)realloc(p, 40);
	printf("%p %p\n", p, p2);
	//free(p);    !!!这是错误的多此一举
	//p = NULL;   realloc函数已经自动将p处理了
	int i = 0;
	for (i = 5; i < 10; i++)
	{
		*(p2 + i) = 3 * i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p2);
	p2 = NULL;
	return 0;
}

到了这里,关于第五十三天学习记录:C语言进阶:动态内存管理Ⅰ的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 第五十三章 Unity 移动平台输入(上)

    在移动设备上,Input 类提供对触摸屏、加速度计和地理/位置输入的访问。这里我们简单介绍Input类对于触摸屏的支持。Input.Touches是一个触摸数组,每个数组元素代表着手指在屏幕上的触碰状态Input.Touch。Input.Touch 数据结构表示: fingerId 触摸索引 deltatime 从最后状态到当前状态

    2024年02月03日
    浏览(27)
  • kettle从入门到精通 第五十三课 ETL之kettle MQTT/RabbitMQ consumer实战

    1、上一节课我们学习了MQTT producer 生产者步骤,MQTT consumer消费者步骤。该步骤可以从支持MRQTT协议的中间件获取数据,该步骤和kafka consumer 一样可以处理实时数据交互,如下图所示:  2、双击步骤打开MQTT consumer 配置窗口,如下图所示: Step name: 自定义步骤名称。 Transformat

    2024年04月28日
    浏览(36)
  • 从零开始搭建搜索推荐系统(五十三)QUERY从分词检索进阶

    聊的不止技术。跟着小帅写代码,还原和技术大牛一对一真实对话,剖析真实项目筑成的一砖一瓦,了解最新最及时的资讯信息,还可以学到日常撩妹小技巧哦,让我们开始探索主人公小帅的职场生涯吧! (PS:本系列文章以幽默风趣风格为主,较真侠和杠精请绕道~) 一、

    2024年02月04日
    浏览(26)
  • 从零开始的力扣刷题记录-第五十八天

    题目描述: 给你一个 不包含 任何零的整数数组 nums ,找出自身与对应的负数都在数组中存在的最大正整数 k 。 返回正整数 k ,如果不存在这样的整数,返回 -1 。 题解: 哈希表存储负数,再遍历nums对每一个正数去哈希表中查找是否存在对应的负数。存在就更新返回值 代码

    2024年02月09日
    浏览(37)
  • SSM框架的学习与应用(Spring + Spring MVC + MyBatis)-Java EE企业级应用开发学习记录(第三天)动态SQL

    昨天我们深入学习了 Mybatis的核心对象SqlSessionFactoryBuilder , 掌握MyBatis核心配置文件以及元素的使用 ,也掌握MyBatis映射文件及其元素的使用。那么今天我们需要掌握的是更加复杂的查询操作。 学会编写MyBatis中动态SQL 学会MyBatis的条件查询操作 学会MyBatis的更新操作 学会MyBati

    2024年02月11日
    浏览(41)
  • 学习Android的第十三天

    目录 Android TextClock 文本时钟控件 TextClock 控件主要属性和方法 简单的 TextClock 参考文档 Android AnalogClock 控件 AnalogClock 属性 Android Chronometer 计时器 Chronometer 属性 Chronometer 主要方法 范例: 完整的计时器 范例: 倒计时 Android TextClock 是一个用于在 Android 应用中显示当前日期和时

    2024年02月19日
    浏览(34)
  • 学习java第四十三天

    Spring AOP 相关术语 (1)切面(Aspect):切面是通知和切点的结合。通知和切点共同定义了切面的全部内容。 (2)连接点(Join point):指方法,在Spring AOP中,一个连接点总是代表一个方法的执行。连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时

    2024年04月15日
    浏览(33)
  • 学C的第三十三天【C语言文件操作】

    ========================================================================= 相关代码gitee自取 : C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 学C的第三十二天【动态内存管理】_高高的胖子的博客-CSDN博客  =====================================

    2024年02月13日
    浏览(27)
  • 【AI视野·今日NLP 自然语言处理论文速览 第五十三期】Thu, 12 Oct 2023

    AI视野 ·今日CS.NLP 自然语言处理论文速览 Thu, 12 Oct 2023 Totally 69 papers 👉 上期速览 ✈更多精彩请移步主页 To Build Our Future, We Must Know Our Past: Contextualizing Paradigm Shifts in Natural Language Processing Authors Sireesh Gururaja, Amanda Bertsch, Clara Na, David Gray Widder, Emma Strubell NLP 正处于一个颠覆性变

    2024年02月07日
    浏览(34)
  • 【AI视野·今日NLP 自然语言处理论文速览 第五十四期】Fri, 13 Oct 2023

    AI视野 ·今日CS.NLP 自然语言处理论文速览 Fri, 13 Oct 2023 Totally 75 papers 👉 上期速览 ✈更多精彩请移步主页 Tree-Planner: Efficient Close-loop Task Planning with Large Language Models Authors Mengkang Hu, Yao Mu, Xinmiao Yu, Mingyu Ding, Shiguang Wu, Wenqi Shao, Qiguang Chen, Bin Wang, Yu Qiao, Ping Luo 本文研究闭环任务规

    2024年02月07日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包