IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 动态内存分配 -> 正文阅读

[数据结构与算法]动态内存分配

动态内存分配



前言

我们都知道,在存储一些相同数据类型的元素时,我们会使用到数组。但是,我们来考虑一种情况,当我们不知道元素个数时,如何指定数组的大小呢,这种情况下,我们可能会指定一个较大的空间的数组,因为其能容纳更多的元素。

但是这么做同样会有问题,比如说存储的元素很少,就会造成大量数组空间的浪费。但是如果把数组空间设置的小一点来减少浪费,就有可能会出现数组空间不够用的情况了。这就是我们为何要使用动态内存分配。


一、malloc和free

C语言的函数库提供了malloc和free两个函数,分别用来执行动态内存的分配和释放。这些函数维护一个可用的内存池。

1.malloc

当程序需要存储数据时,它就调用malloc函数,从内存池中找到一块合适的内存,同时返回一个指向该内存的指针。

这块分配的内存是没有经过初始化的,若有初始化的要求,要么自己对其进行初始化,要么使用另外一个内存分配函数calloc(下面会讲到)

下面是一个使用动态内存分配的例子:
代码如下:

	int* p;
	int len = 10;
	p = malloc(len * sizeof(int));
	if (p == NULL)
	{
		exit(1);
	}

malloc函数的参数是要分配内存的字节数,如果内存池中的可用内存足够,malloc就返回一个指向起始位置的指针。其返回值类型是一个void* 的指针,它可以转换为任何其他类型的指针。

如果内存池是空的,或者说内存池空间不够。malloc函数就会向操作系统请求得到更多的内存,并在新内存上执行分配任务。那如果操作系统无法向malloc函数提供内存,malloc函数就会返回一个NULL指针。

So,在请求动态内存分配之后一定要检查指针是否为空

2.free

那么,当我们使用完这块内存之后不想再使用了,就要把它还给内存池以供接下来的使用。要把内存还回去就要调用free函数。

代码如下:

	int* p;
	int len = 10;
	p = malloc(len * sizeof(int));
	if (p == NULL)
	{
		exit(1);
	}
	//释放
	free(p);
	p = NULL;

free函数的参数要么是空指针,要么是之前从malloc、calloc和realloc返回的值。给free函数传递一个空指针不会产生任何效果。

最后将p变成空指针是为什么呢?

当我们free掉动态分配的内存以后,这个指针指向的内存空间就会还给内存池,以供接下来的使用。但是此时我们的p指针依然指向的了这个位置。如果不把其置为空指针,就可能会对后来的使用产生影响。当这个位置分配给其他指针时,我们再去调用就会产生无法预计的后果。

同时free函数不能只释放一部分的动态分配的内存。也不能释放非动态分配的内存。同时要注意释放之后的存储不能再继续使用了。

二、calloc和realloc

1.calloc

calloc函数也用于动态分配内存。malloc和calloc函数的区别主要是后者在返回指向内存的指针之前将其初始化为0。如果你希望这样初始化的话,就可以使用calloc函数。

另外一个小区别时,calloc函数的参数一个是元素的数量,一个是这种元素所对应的字节数量,calloc函数可以自行计算出需要分配的内存大小。

代码如下:

	int* p;
	int len = 10;
	p = calloc(len, sizeof(int));
	if (p == NULL)
	{
		exit(1);
	}

2.realloc

如果动态分配的内存大小随着我们的使用依然不够了。要怎么办呢?

realloc 函数用于修改一个原先已经分配的内存块的大小。通过这个函数,可使已经分配的内存变大或者变小。

如果它用于扩大一个内存块,那么原先的内容依旧保留,同时新增的内存添加到原先内存的后面,同时要注意,新内存是没有初始化的。

如果它用于缩小一个内存块,该内存块尾部的相应大小就会被拿掉,剩余部分的内存保持不变。

如果原先的内存块大小无法改变,realloc将分配另一块正确大小的内存,并把原先的那块内存的内容复制到新的内存块上。

因此,在使用realloc之后,就不能再使用指向旧内存的指针了,而是应该使用realloc返回的新指针。

如果realloc函数的第一个参数是NULL,那么它的作用就和malloc一模一样。
代码如下:

	int* p;
	int len = 10;
	p = calloc(len, sizeof(int));
	if (p == NULL)
	{
		exit(1);
	}
	int i = 0;
	for (i = 0; i < len; i++)
	{
		scanf("%d", p + i);
	}
	len += len;
	
	p = realloc(p, len * sizeof(int));

三、内存泄漏

当动态分配的内存不再需要时,应该被释放,这样它以后可以被重新分配使用。如果只分配内存,但是在使用完毕后不释放将引起内存泄漏(memory leak)。在那些所有执行程序共享一个通用的内存池的操作系统中,内存泄漏会一点一点的榨干可用内存,最终使其一无所有。

其他操作系统能够记住每个程序当前拥有的内存段,这样当一个程序终止时,所有分配给它但是未被释放的内存都归还给内存池。

但是在这种系统中,内存泄漏仍然是一个严重的问题,因为一个持续分配内存却一点也不释放内存的程序最终一定会耗尽所有可用内存。此时,这个有缺陷的程序将无法继续执行下去,同时它的失败可能会导致当前已经完成的工作统统丢失。


总结

malloc和calloc函数都用于动态分配一块内存,并返回一个指向该内存块的指针。但是它们的参数不同malloc的参数是分配内存的字节数,而calloc是元素个数和元素类型的大小,同时calloc可以将动态分配的内存初始化为0.

realloc函数可以改变一块已经动态分配内存的大小

如果一个动态内存分配的内存块不再使用,应及时调用free函数将其释放,归还给内存池。同时,释放之后便不能再访问。

若动态分配内存失败,将会返回NULL。同时应当注意不能越界访问动态分配的内存,不能释放非动态分配的内存、不能只释放动态分配内存的一部分。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-21 17:37:43  更:2021-12-21 17:37:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:22:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码