动态内存管理C进阶

Posted 林慢慢i

tags:

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

前言:本章将介绍4个常用的动态内存函数以及使用过程中的常见错误。



为什么需要动态内存分配?

我们已知的内存开辟方式:

1.在栈空间上开辟4个字节

int a=20;

2.在栈空间上开辟10个字节的连续空间

char a[10]={0};

已知开辟空间的方式有两个缺点:

1.空间开辟大小是固定的。

2.数组在声明的时候,必须指定数组长度,它所需要的内存在编译时已经分配。

但是有时候我们需要的空间大小在程序运行的时候才能知道,那数组在编译时开辟的空间可能无法满足,这时候只能试试动态内存开辟了。

动态内存都是在堆中开辟的:



几个动态内存函数的介绍

malloc

一个动态内存开辟的函数,原型如下:

void* malloc(size_t size);

这个malloc函数向内存申请一块连续可用的空间,并返回指向这块空间的指针,有以下几个特点:

如果开辟成功,则返回一个指向开辟好空间的指针。

如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查

如果返回值的类型是void*,那么malloc函数并不知道开辟空间的类型,具体由使用者决定。

如果参数size为0,malloc的行为是标准未定义的,取决于编辑器。

示例程序:

//假设开辟10个整形的空间 - 10* sizeof(int)
int arr[10];//栈区
//动态内存开辟的
int* p = (int*)malloc(10*sizeof(int));
if (ptr == NULL)
	{
		return 1;
	}
for (i = 0; i < 10; i++)
	{
		printf("%d\\n", *(p + i));
	}

	free(p);
	p = NULL;

注释:判断指针是否为空是必须的!

free

专门用来做动态内存的释放和回收的函数,原型如下:

void free(viod*ptr)

free函数用来释放动态开辟的内存。

如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。

如果参数ptr是NULL指针,则函数什么事都不做。

malloc和free都声明在stdlib.h头文件。

示例程序:

int main()
{
	int* ptr = (int*)malloc(sizeof(int) * 4);
	if (ptr != NULL)
	{
		for (int i = 0; i < 4; i++)
		{
			ptr[i] = i;
			printf("%d ", ptr[i]);
		}
	}
	
	free(ptr);//思考这一步必须有吗?
	ptr = NULL;//思考这一步是必须的吗?
	return 0;
}

注释:free(ptr);是必须的,因为malloc开辟出来的空间是在堆上,使用完一定要记得释放否则就造成内存泄漏,ptr = NULL;也是必须的,因为ptr在free之后仍然指向开辟的空间,但开辟的空间已经还回去了,所以我们要手动置成NULL。

calloc

calloc函数也用动态内存分配,原型如下:

void* calloc(size_t num,size_t size);

为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。

与函数malloc的区别在于calloc会在返回地址之前把申请的空间的每个字节初始化0.

示例程序:

int main()
{
	int* p = calloc(10, sizeof(int));

	if (p == NULL)
		return 1;

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\\n", *(p + i));
	}

	free(p);
	p = NULL;

	return 0;
}

注释:calloc开辟出来的空间也是在堆区上,使用完之后需要对内存进行释放,同时也要判断是否能开出了来,并置成NULL。

realloc

有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,需要对内存的大小做灵活的调整,而 realloc 函数就可以做到对动态开辟内存大小的调整。

函数原型如下:

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

其中参数ptr是要调整的内存地址,size为调整之后的大小,下面分析,realloc扩容是的两种情况:

第一种:原空间后面有足够大的空间

第二种:原空间后面没有足够大的空间

除此之外,当realloc所需开辟的内存过大开不,也是会返回NULL,所以我们依旧要对返回值进行判断!

示例程序:

int main()
{
	int* p = (int*)calloc(10, sizeof(int));

	if (p == NULL)
	{
		perror("main");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 5;
	}
	//假设这里需要p指向的空间更大,需要20个int的空间
	//realloc调整空间
	int*ptr = (int*)realloc(p, 20*sizeof(int));
	if (ptr != NULL)
	{
		p = ptr;
	}

	free(p);
	p = NULL;

	return 0;
}


动态内存使用中的常见错误

1.未判断指针是否为NULL,直接解引用(即对NULL指针解引用)

2.对动态开辟空间的越界访问

3.对非动态开辟内存使用free释放

4.过早使用free释放掉一块后期还需使用的动态内存

5.对同一块动态内存多次释放

6.动态开辟的内存忘记释放(造成内存泄露)



动态内存管理部分到此介绍结束了,感谢您的阅读!!!如果内容对你有帮助的话,记得给我三连(点赞、收藏、关注)——做个手有余香的人。

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

C语言进阶动态内存管理

动态内存管理C进阶

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

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

C语言进阶想用好C++?那就一定要掌握动态内存管理

《C语言深度剖析》第五章 内存管理 p1(完结)( C语言从入门到入土(进阶篇)