【c语言】【visual studio】动态内存管理,malloc,calloc,realloc详解。

发布时间:2023年12月17日

引言:随着大一期末的到来,想必许多学生都学到内存的动态管理这一部分了,看望这篇博客后,希望能解除你心中对这一章节的疑惑。

(???(???(???*)

fcd86daf76774b47ba0f81a14548685a.png

1.malloc详解

malloc的头文件是#include <sdtlib.h>,malloc - C++ Reference (cplusplus.com)

我们可以点进看看的malloc的详细内容

3cd425feee5846778cd6204de797177d.png

可以看到malloc返回值是void*类型,也就是说明在使用时我们还需要根据需要开辟空间的类型,强制类型转换成自己所要的类型。例如我们要开辟40个字节的空间,代码如下。

#include <stdlib.h>
int main()
{
	int* pa =(int *) malloc(10 * sizeof(int));
	return 0;
}

用数组的来写,如下

同样也可以实现空间的开辟,这里我们就来谈谈相同点与不同点。

#include <stdio.h>
int main()
{
	int pa[10];
	return 0;
}

相同点:

  1. 向内存申请一块空间
  2. 在程序结束时释放

不同点:

  1. 申请的内存位置不同,malloc在堆区,数组在栈区。
  2. 头文件不同,malloc头文件是<stdlib.h>,数组头文件是<stdio.h>
  3. 空间动态性,malloc所申请的空间是可变的,动态的可以通过使用realloc(下面会再讲解realloc的用法)来改变大小,数组所申请的空间是不可变的,定义完后就固定了。
  4. 数组定义时可以初始化空间内容,malloc申请空间时不能初始化内容,且其空间里的内容是随机值。
  5. malloc申请空间可能失败,数组不会。

如何理解这些不同点以及如何配套使用malloc我们看下面这一段代码

#include <stdlib.h>
int main()
{
	int* pa =(int *)malloc(10 * sizeof(int));
	if (pa == NULL)
	{
		perror("malloc:");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(pa+i) = i;
		printf("%d ", *(pa+i));
	}
	free(pa);
	pa = NULL;
	return 0;
}

我们可以看到,用malloc申请完空间后,我们接着写了一段代码判断pa是否为NULL

fb0cc24487d9448289e0ac175d8333be.png

我们接上不同点5,malloc申请空间可能会失败。所以我们要分类讨论malloc申请空间的情况

1.失败返回NULL(空指针)。

2.成功返回申请到空间的首地址。

至于perror是一种打印申请空间失败原因的库函数,我们可写可不写,为了可读性最好加上,接着如果失败我们return 1结束程序。因为以及申请失败了,下面的代码是针对成功的情况,如果不结束程序,代码就会出错。

?9bb6ee7f7f094c9dbd5a88e62f78cb24.png

for循环将0到9输入到这片空间中,并打印到屏幕中,

最后使用完了这块空间,我们free释放掉(free是编译器里的库函数,用来释放某一块空间的),还回去。释放完后free函数并不会将pa置为NULL,为了防止野指针的出现,我们需要手动设为NULL.

778302513ac743838f3e96d42e4f4baf.png

2.calloc详解

calloc和malloc很类似也是申请一块空间,我们接着看。

calloc的头文件是#include <sdtlib.h>calloc - C++ Reference (cplusplus.com)

我们可以点进看看的calloc的详细内容

f46de5c5d65f49d69189099f1fb19707.png

同样我们可以看到calloc的返回值是void*,但calloc函数比malloc多了一个参数。我们具体分析

194835d2bdfc40aa9afec011b6981671.png

具体了解calloc。我们比较calloc与malloc

相同点:

1.都是向堆区申请一块空间。

2.都是动态的,可变的。

3.成功返回这块空间的首地址,失败返回NULL。

4.函数返回值都是void*。

不同点:

1.申请的空间成功时可以初始化为0,而malloc不可以。

至于不同点,我们看代码

?
?
#include <stdlib.h>
int main()
{
	int* pa =(int *)calloc(10 , sizeof(int));
	if (pa == NULL)
	{
		perror("calloc:");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(pa+i));
	}
	free(pa);
	pa = NULL;
	return 0;
}

?

?

我们没有给calloc申请的空间赋值,我们看结果是

14578fd50b9b4057a61f63056bca345e.png

申请空间后初始化为0。

3.realloc详解

realloc的头文件是#include <sdtlib.h>realloc - C++ Reference (cplusplus.com)

我们可以点进看看的calloc的详细内容

a37387374e5144e3803092551cdd7b8f.png

看功能,realloc是来调整malloc/calooc申请的空间。与数组的不同就体现在这。

具体分析realloc的两个参数:

ad2be7e231fa40058d6c6673b3be2dea.png

具体我们看代码操作:
?

?
#include <stdlib.h>
int main()
{
	int* pa = (int*)malloc(5 * sizeof(int));
	if (pa == NULL)
	{
		perror("mallco:");
		return -1;
	}
	for (int i = 0; i < 5; i++)
	{
		*(pa + i) = i;//pa需要+i指向下一个位置。
		printf("%d ", *(pa + i));
	}
	int* pb = (int*)realloc(pa, 10 * sizeof(int));
	if (pb == NULL)
	{
		pb = pa;
		free(pb);
		pb = NULL;
		perror("realloc:");
		return 1;
	}
	else
		pa = pb;
	for (int i = 5; i < 10; i++)
	{
		*(pa + i) = i;//pa需要+i指向下一个位置。
		printf("%d ", *(pa + i));
	}
	free(pa);
	pa = NULL;
	return 0;
}

?

代码上半部分用malloc申请一块空间后,我们觉得20字节大小不够,我们就使用realloc函数增大空间至40个字节大小。同样申请完后我们要判断申请是否成功。

bf37312dedff44bb9c164f4c8c725450.png

这里realloc比较复杂。我们一一述说:
1.失败返回NULL。

2.成功有分为两种情况

  1. 在申请时太大占用了其它已经占用空间时realloc会在内存的堆区重新找一个满足条件的空间,同时把旧的数据copy到新的空间,接着释放旧空间,同时返回新空间的起始地址。
  2. 在申请时空间够用时,返回起始地址。

所以如果pb==NULL时申请失败,我们需要把之前malloc申请的空间释放掉。并置为NULL。

总结:malloc,calloc,realloc三者都是void*类型函数,接收返回值时都要强制类型转换。在堆上申请的空间要即使释放,并置为空指针。每次申请完后要判断申请是否成功等等。

以上希望能够帮到你,让你对动态内存管理有跟深的理解。

文章来源:https://blog.csdn.net/yanlou233/article/details/134936494
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。