超详细的C进阶教程!动态内存管理

Posted 东条希尔薇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了超详细的C进阶教程!动态内存管理相关的知识,希望对你有一定的参考价值。

作者的码云地址:https://gitee.com/dongtiao-xiewei
后续作者会更新力扣的每日一题系列,原代码会全部上传码云,推荐关注哦,笔芯~

还像更深入地了解c语言?快来订阅作者的c语言进阶专栏!作者承诺本系列不会TJ!预计更新:指针,字符串处理,内存管理,结构体,预处理等等

我们在以前的文章中提到,其实计算机的内存分为以下三个区

  1. 栈区:用于存放临时变量,形式参数
  2. 堆区:用于动态内存管理
  3. 静态区:用于存放静态变量,全局变量等

而我们今天要讨论的动态内存管理,则是在堆区上创建的

一般来说,堆区的空间比栈区要大,堆区大约有几个G的内存而栈区可能只有几百M

引例

为什么会存在动态内存分配?

比如,我们要实现这种变长数组

int n=0;
scanf("%d",&n);
int a[n]={0};

这个数组的长度在使用前我们是不知道的,所以用一个变量来代替

但是,这个代码并不一定在所有编译器上都能编译成功,所以导致了一个可移植性的问题

但用动态内存管理,就能解决变长数组的跨平台问题了

int n=0;
scanf("%d",&n);
int* arr=(int*)malloc(sizeof(int)*n);

这个代码可以在堆区开辟n个整型的空间

亦或者,比如力扣第一题

我们需要返回一个int*,也就是一个整型数组
但返回方式就只能先在堆上开辟空间,进行修改后再返回这一块空间起始位置的指针

因为,在函数内开辟的数字,出了函数是要销毁的,所以不能直接返回

所以,动态内存管理是C语言一个重要的部分

而要介绍这一章的内容,核心是以下的几个函数

注意,动态内存函数需要<stdlib.h>头文件!

动态内存函数介绍

malloc函数

函数有一个参数,代表需要开辟空间的大小,单位字节

这个函数的功能是在堆上开辟一块连续的空间,函数返回一个void指针,指向这块空间的起始位置

int* arr = sizeof(20);开辟20字节的空间,由int接受

但你需要注意:这个函数的返回类型是void*类型,万能接受指针,使用前最好强制类型转换一下,与数组类型匹配

int* arr = (int*)sizeof(20);

如果此函数开辟失败,则返回一个NULL指针

所以,在使用空间前,一定要检查有效性

int main()
{
	int* arr = (int*)malloc(20);
	if (!arr)
	{
		printf("fail\\n");
		exit(-1);
	}
	else
	{
		//操作
	}
	return 0;
}

有什么情况会返回失败呢?
当然有,你开辟的空间过大,将会开辟失败!

calloc函数

这个函数有两个参数,第一个参数代表开辟的元素个数,第二个参数代表每个元素占的字节数

另外,这个函数会自动将这块空间初始化为0,但malloc不会
以下两个数组是等价的

int arr[10] = { 0 };
int* arr1 = (int*)calloc(10, sizeof(int));

free函数

这个函数的参数是一个地址,可以将指向的这块动态管理的空间释放掉

使用示例:

int main()
{
	int* arr = (int*)malloc(20*sizeof(int));
	if (!arr)
	{
		printf("fail\\n");
		exit(-1);
	}
	else
	{
		//操作
	}
	return 0;
}
free(arr);
arr=NULL;//这步有必要吗

最后一句虽然可以去掉,但这个语句却非常重要

因为将空间释放掉了,这块空间就还给操作系统了就不属于我们了!这个指针也成了俗话说的野指针

所以,最后一句可以防止野指针问题

我们在编程中,为了防止内存泄露在此空间使用完成后,必须及时释放掉!

realloc函数

这个函数两个参数,第一个为一个数组,第二个是一个大小

这个函数的功能是将原数组调整到指定大小!

使用示例
注意:需要一个中间变量来交换**(会自动将原数组数据拷贝),同样需要检查有效性**

int main()
{
	int* arr = sizeof(20);
	if (!arr)
	{
		printf("fail\\n");
		exit(-1);
	}
	int* tmp = realloc(arr, 100);
	if (!tmp)
	{
		printf("fail\\n");
		exit(-1);
	}

	else
	{
		arr = tmp;
		//操作
	}
	return 0;
}

完整的动态空间使用示例

int main()
{
	int* arr = (int*)malloc(sizeof(int) * 10);
	if (!arr)
	{
		printf("fail\\n");
		exit(-1);
	}
	for (int i = 0; i < 10; i++)
	{
		arr[i] = i;
		printf("%d ", arr[i]);
	}
	int* tmp = (int*)realloc(arr, 20 * sizeof(int));
	if (!tmp)
	{
		printf("fail\\n");
		exit(-1);
	}
	arr=tmp;
	for (int i = 11; i < 20; i++)
	{
		arr[i] = i;
		printf("%d ", arr[i]);
	}
	free(arr);
	arr = NULL;
	tmp = NULL;
	return 0;
}

输出结果

总结与提示

  1. 使用动态空间时一定要检查空间开辟是否成功
  2. 你最好不要越界访问,对程序没有什么好处
  3. 不要去尝试对非动态开辟内存执行free函数
  4. free这块空间时,严禁修改指向这块空间的指针值

以上是关于超详细的C进阶教程!动态内存管理的主要内容,如果未能解决你的问题,请参考以下文章

C语言进阶:动态内存管理

C语言进阶动态内存管理

动态内存管理C进阶

⭐️欢度国庆-共约C语言进阶⭐️ 动态内存管理+柔性数组 建议收藏

C语言进阶四.动态内存管理

超详细的c进阶教程!手撕c指针