【C语言】动态内存管理

一.内存分配

1.内存分配方式

内存分配方式有三种:

①.从静态储存区域分配

内存在程序编译的时候就已经分配好,这块内存空间在整个程序运行期间一直存在。例如全局变量、static变量等。

②.在栈上创建

在调用函数的时候,其内部的局部变量的存储单元在栈上创建,函数执行结束时局部变量被销毁,存储单元被回收释放。栈内存分配运算内置于处理器的指令集中,效率很高,但分配的空间大小有限。

③.从堆上分配

也称为动态内存分配,程序员使用malloc或new申请任意大多少的内存,然后用free或者delete释放空间,动态内存的生存期由程序员决定。这种动态申请空间显然比较灵活,但同时也很容易出现错误。
如图所示:
在这里插入图片描述

2.动态内存分配的概念

之前的博客里面讲到过变量创建的本质是申请空间,但是这是一次性开辟的一块固定大小的空间,所以难免会出现空间分配过大,或者分配不足的情况,因此这时候我们要学习一个新东西,那就是动态内存管理。
所谓动态内存分配,就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。
动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

二.动态内存分配函数

C/C++提供了四个动态存储分配函数,使用时要加上头文件<stdlib.h>。(new和delete是C++的运算符)

1.malloc

在这里插入图片描述

函数原型为:

void * malloc (size_t size) ;

参数 size 为申请内存空间的大小,单位是字节。
功能为:
分配一块内存空间,单位是字节。返回值为所分配内存空间的起始地址,如果没有成功申请空间,则返回一个NULL指针

int main()
{
	int*p=(int *)malloc(40);//申请40个字节的空间
	//因为指针P类型为int*,所以要将malloc的返回值强制转换成int*。

	//判断malloc是否成功申请空间
	if (p == NULL)
	{
		perror(malloc);//打印错误信息
		return 1; //返回1,即异常返回
	}
	//走到这里说明成功分配了40个字节的空间,那么就可以使用了
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

运行结果如图:
在这里插入图片描述
补充:
①.这块被分配的内存空间并没有被初始化,它的值是不确定的。
②.如果参数size是0,那么返回值取决于特定的库实现,可能是或者不是一个空指针。

2.free

在这里插入图片描述
函数原型为:

void free (void* ptr ) ;

参数 ptr 为指向由动态内存分配函数所开辟的空间的指针。
功能为:
释放由malloc、calloc或realloc动态分配的内存空间,无返回值。
上面的代码有一个很大的问题,就是动态开辟一块空间使用完之后没有释放掉,这时我们就需要free函数来释放和回收动态开辟的空间。

	free(p); //释放
	p = NULL;//释放完要及时将p置为空指针,否则p就是个野指针。

加上这两行代码,问题才被解决。
补充:
①.如果使用free释放非动态分配的空间,会导致未定义的结果。
②.如果参数ptr是个空指针,那么这个函数什么也不做。
③.使用函数后,参数ptr所指向的内存被释放了,但ptr仍然所指的地址不变,即现在ptr已经成为了野指针,如果不及时的将ptr置为空指针(NULL),可能出现错误。

3.calloc

在这里插入图片描述
函数原型为:

void*calloc (size_t num, size_t size) ;

参数1 num为需要分配空间的数据个数,参数2 size为每个数据的大小,单位是字节。
功能为:
num个数据分配连续的内存空间,每个数据为大小为size,并且将每个数据都初始化为0。
返回值为分配内存单元的起始地址,如果未成功申请空间,则返回一个NULL指针。

int main()
{
	int*p=(int *)calloc(5,4);//为5个整型数据申请20个字节的空间
	//因为指针P类型为int*,所以要将calloc的返回值强制转换成int*。

	//判断calloc是否成功申请空间
	if (p == NULL)
	{
		perror(calloc);//打印错误信息
		return 1; //返回1,即异常返回
	}
	//走到这里说明成功分配了20个字节的空间,那么就可以使用了
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", *(p + i));
	}
	free(p); //释放
	p = NULL;//释放完要及时将p置为空指针,否则p就是个野指针。
	return 0;
}

打印结果如图:
在这里插入图片描述

补充:
①.如果参数size是0,那么返回值取决于特定的库实现,可能是或者不是一个空指针。

4.realloc

在这里插入图片描述
函数原型为;

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

参数1 ptr 为指向已经由malloc,calloc或realloc分配过的空间的指针,参数2 size为给参数ptr所指向的地址新分配的空间,单位为字节。
功能为:
给ptr所指向的地址重新分配大小为size的空间。返回重新分配的空间的地址,可能是原来ptr所指向的地址,也可能一个新的地址。
realloc重新分配空间有三种情况:
①.原空间后面有足够的空间增容,直接增容,并将原空间地址返回。
在这里插入图片描述

②.原空间后面的空间不足,寻找新的空间,并将原空间的数据移植到新的空间后,将原空间内存释放。返回新空间的地址。
在这里插入图片描述
③.原空间后面空间不足,且无法寻找到新的地址,返回一个空指针。

三.注意事项

发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到。大家要通过多加练习,丰富经验的方式来减少出错的机率。

码字不易,多谢大家支持🌹
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值