练习使用动态内存相关的函数

本文详细介绍了C语言中的动态内存管理函数malloc、calloc、realloc和free,包括它们的功能、使用技巧以及注意事项,强调了malloc和free的配合以及内存释放的重要性,以防内存泄漏。
摘要由CSDN通过智能技术生成

前言

练习使用动态内存相关的4个函数,并调试观察

malloc、calloc、realloc、free

1.malloc

malloc函数在内存堆区申请一块空间,并返回指向这块空间的地址;

如果开辟失败,则返回NULL;

可以将malloc开辟的这块空间类比成一个数组,即我们利用malloc在堆区中开辟了一个数组;

我们可以看到,malloc函数的返回值是一个void*类型的指针(该指针指向这块空间的首元素地址),所以我们可以开辟的空间可以是任意类型,即我们可以开辟出一个任意类型的数组;

如下,如果我们想要开辟处一个int类型的空间:

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

int main()
{
	int i = 0;
	int* arr = malloc(5 * sizeof(int));
	for (i = 0; i < 5; i++)
	{
		*(arr + i) = i + 1;
	}
	for (i = 0; i < 5; i++)
		printf("%d ", arr[i]);
	printf("\n");

	return 0;
}

运行如下:

这里malloc中传入的参数是字节数,在这里其实就能决定了我们开辟空间的类型,那我们就有了一个小技巧:

如果我们已经确定要开辟num个(类型)的空间,那我们传入的参数就可以写成num*sizeof(类型名);

但是很明显,这段代码是存在问题的,下面我们就来介绍一下

1.1.malloc函数的注意事项

我们知道,malloc会在内存中开辟处一块空间,但是malloc不是一定能开辟成功,例如:

此时malloc中的参数是一个非常非常大的数,在这里我们可以看到,当需要的空间过大或者一些其他原因,malloc可能就无法成功开辟,返回的是NULL,那这个返回值就无法正常使用;

因此

malloc的返回值一定要检查,因此,最开始的那一段代码应当加上检查部分:

int main()
{
	int i = 0;
	int* arr = malloc(5 * sizeof(int));
	if (arr == NULL)
	{
		perror("malloc");
		return 1;
	}
	for (i = 0; i < 5; i++)
	{
		*(arr + i) = i + 1;
	}
	for (i = 0; i < 5; i++)
		printf("%d ", arr[i]);
	printf("\n");

	return 0;
}

一旦开辟不成功,perror就会帮我们指出来,这个时候应该提前结束程序:

2.calloc

在介绍完malloc之后,我们再来看一个和malloc函数的作用几乎相似的函数——calloc,这个函数同样是在内存中开辟一块空间,但传入的参数有两个,num和size,即num个size大小的空间,但他和malloc函数最大的不同点便是calloc会对开辟的空间进行初始化,如下: 

int main()
{
	int* arr = calloc(5, sizeof(int));
	if (arr == NULL)
	{
		perror("calloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");

	return 0;
}

要注意,calloc函数也需要对返回值进行检查,他也不是一定能成功开辟出空间;

在实际应用的过程中,我们可以根据自身需要选择使用malloc函数或者是calloc函数,但calloc函数比malloc函数多出一个步骤,其执行速度必然是比不上malloc的;

3.free

C语言还提供了一个函数free,专门用来动态内存的释放和回收;

如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。
如果参数 ptr 是NULL指针,则函数什么事都不做。

我们直接来看一段代码

int main()
{
	int i = 0;
	int* arr = malloc(5 * sizeof(int));
	if (arr == NULL)
	{
		perror("malloc");
		return 1;
	}
	for (i = 0; i < 5; i++)
	{
		*(arr + i) = i + 1;
	}
	for (i = 0; i < 5; i++)
		printf("%d ", arr[i]);
	printf("\n");

	free(arr);
	arr = NULL;

	return 0;
}

这段代码与上面代码唯一不同的地方便是加上了free,当我们用完malloc函数开辟出来的空间之后,应该将他还给内存;

其实在程序结束后,系统也会自动回收我们开辟的内存空间,那这个函数的用处体现在什么地方呢?我们再来看这一段代码:

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

不是所有的程序都会结束,现在几乎所有的大企业,他们公司的程序可能是一天24小时不间断地走,像这一段代码,他陷入了循环,整个程序就不会结束,当程序持续执行的时候,我们申请的内存空间却还是占用着内存的空间,这难免会造成一些不良的影响;

内存真的很宝贵,系统中的每一处内存都有其必要的用处,当我们申请完一处内存空间后,如果不将其回收,他就会一直储存在我们的内存中,这种情况称为内存泄漏,我们申请的空间越来越多,但却没有将它的使用权限还给系统,那这样我们的服务器就会越来越卡,直到最后就会崩掉,所以为什么要释放掉,就是这个原因;

因此:malloc和free是要成对出现的;

在此基础上,我们还要再注意一个点,我们来看一段代码和他的运行结果:

我们可以发现,free前后pa的值是一直没有改变的,但是经过释放,我们已经把pa所指向的空间还给了内存,那这块空间就无法使用,当我们写的代码过多,我们或许又会不小心使用到pa,那这个时候会发生什么呢?

我们通过一段代码和他的调试来更清晰地了解这个过程:

int main()
{
	int* arr = (int*)malloc(5 * sizeof(int));
	if (arr == NULL)
	{
		perror("malloc");
		return 1;
	}
	int* pa = arr;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		arr[i] = i + 1;
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}

	printf("\n");

	free(arr);
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}


	return 0;
}

这是开辟后和赋值的全过程,那这个时候我们想打印出开辟出内存中的值:

没有问题;

那在使用free释放之后呢,我们先看右边调试时内存中的值的变化;

在释放之后,内存中的值就已经全部改变了,因为它已经被内存回收,这块空间的使用权限已经不属于我们了,所以我们就不可能将其再次使用并打印出来;

所以说,在每次使用完free之后,一定要将其置空,免得程序使用故障;

如下;

free(arr);
arr = NULL;

这就是free有关的内容,我们再来看一下realloc函数的介绍:

4.realloc

realloc函数的出现让动态内存管理更加灵活
有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的使
用内存,我们⼀定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。
ptr 是要调整的内存地址
size 调整之后新大小
返回值为调整之后的内存起始位置。
这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。


realloc在调整内存空间的是存在两种情况
情况1:原有空间之后有足够大的空间
情况2:原有空间之后没有足够大的空间

下面来画一张图供大家理解:

这里需要注意,realloc同样不是一定能够成功开辟的,开辟不成功时同样会返回NULL,因此在使用realloc的时候,最好创建一个临时变量接收其返回值,并对其进行验证,开辟成功后再将其放到用来维护他的变量中,这样可以保证在开辟空间失败后,原有的数据也不会损失如下:(还是想让arr继续维护这一块空间):

int main()
{
	int* arr = (int*)malloc(5 * sizeof(int));
	int* ptr = (int*)realloc(arr, 10 * sizeof(int));
	if (ptr != NULL)
	{
//......
		arr = ptr;
		ptr = NULL;
	}
//......

	return 0;
}

C语言有了动态内存开辟,程序员的发挥就更加灵活,我们在平常学习C/C++的时候,一定要熟练掌握动态内存的开辟;以上就是这篇文章的全部内容。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值