一动不动是王八?动态内存有话说

前言

一动不动是王八,出自2014年的春晚,小时候经常喜欢说这句话,那在我们C语言中,我们知道,通常我们开辟一块空间用于存放变量的时候,这块空间是不会改变大小的,但是有的时候,需要我们程序运行起来才会知道我们需要多大的内存空间,那这种情况下,我们只能创建一个很大的数组,用来存放,这个时候就出现了不必要的浪费,那这个时候,就出现了我们的动态内存,让我们的内存不在做“王八”。

动态内存函数介绍

malloc

在这里插入图片描述

malloc,一个用于开辟连续内存空间的函数,它可以像内存申请一块空间,然后返回这块空间起始地址的指针,对于我们的malloc来说,如果这块空间申请失败的话,会返回我们的空指针NULL,那同时我们看到malloc的返回类型是void*,因为我们的malloc是不知道我们申请的空间是给什么类型去使用的,所以我们一般会对申请下来的空间进行强转,我们给malloc传过去的size代表着我们需要申请多少个字节的空间,在C语言标准中,是没有明确规定我们的size等于0会发生什么,所以当size等于0的时候,会发生什么取决于编译器,如果我们想用malloc申请一块20个字节的空间给我们char类型的数组str用,那怎么用呢?

int main()
{
	char* str=NULL;
	str=(char*)malloc(20);
	if(str==NULL)
	{
		perror(str);
	}
	return 0;
}

那这样就开辟了一块20个字节的空间给我们的str使用。

free

在这里插入图片描述
free,当我们用动态内存函数开辟空间之后,是需要进行内存释放的,不然就会造成内存泄漏,或者其他问题,这个时候,内存释放用的就是我们的free,它可以对我们开辟的空间进行释放,当我们进行释放之后,我们最好让先前接收这片空间的指针置空,以免造成野指针问题,那有了free之后,我们对于上面的例子代码进行升级。

int main()
{
	char* str=0;
	str=(char*)malloc(20);
	if(str==NULL)
	{
		perror(str);
	}
	free(str);
	str=NULL;
	return 0;
}

calloc

在这里插入图片描述

calloc,和我们的malloc用处是一样的,但是传参是不一样的,对于我们的malloc来说,可以申请任意字节的空间,比如17、21,那这些字节也可以强转给我们的int类型,只不过我们在往申请的这片空间中放东西的时候,因为我们的int类型是4个字节,所以放入到最后字节不够4个字节的空间时,就会产生截断,放不完全,而我们的calloc传的两个参数,第一个是要申请多少个元素,第二个是每个元素的大小,比如我们要为一个10个元素的int类型的数组申请空间,就可以像下面这样来申请。

int main()
{
	int* num=0;
	num=(int*)calloc(10sizeof(int));
	if(num==NULL)
	{
		perror(num);
	}
	free(num);
	num=NULL;
	return 0;
}

其中我们的calloc和malloc还有一个最大的差别,对于我们的malloc来说,它申请下来的空间是不会对其初始化的,所以malloc内存空间里面放的值是不知道的,但是我们的calloc是会对申请的空间进行初始化的,会全部初始化成0。

realloc

在这里插入图片描述

realloc,是让我们内存“动”起来的关键所在,它的作用是我们发现我们用malloc或者calloc申请的空间不够使用的时候,用来“扩容”的,它的参数有两个,第一个就是我们指向我们申请下来那块空间起始地址的指针,第二个就是“扩容”多少个字节,同样,返回的是申请到空间的起始地址,但是如果我们原空间后面的空间不够“扩容”的字节,就会重新找一片空间,然后把原空间的数据拷贝过去,同样,如果申请失败会返回空指针,所以对于我们要“扩容”的时候,最好是在创建一个指针变量,先用新创建的指针变量接收realloc的返回值,然后判断,申请成功就把realloc申请下来的空间赋值给我们的原指针。

int main()
{
	char* str=NULL;
	str=(char*)malloc(20);
	if(str==NULL)
	{
		perror(str);
	}
	char* p=NULL;
	p=(char*)realloc(str,10);
	if(p!=NULL)
	{
		str=p;
		p=NULL;
	}
	free(str);
	str=NULL;
	return 0;
}

柔性数组

柔性数组,于C99标准中定义,它处于结构体当中,当我们结构体的最后一个成员是一个未知大小的数组的时候,就是我们的柔性数组,当然,这个结构体一定要有其他的成员,可能看字看不懂?那我们直接上代码。

struct st_type
{
 	int i;
 	int a[0];//柔性数组
};

这种写法可能在有的编译器上跑不过,那我们就换一种写法。

struct st_type
{
 	int i;
 	int a[];//柔性数组
};

柔性数组特点

我们前面提到,柔性数组之前必须至少有一个成员,那是为什么呢?对于柔性数组,如果用sizeof计算它的大小会是多少呢?我们用编译器试一下。
在这里插入图片描述
我们可以看到,整个结构体大小是4,那为什么是4?一个int就占用了四个内存了,何况我们还有一个数组,这里就直观的说明了,对于我们的柔性数组成员,它是不计入结构体大小的,如果这个结构体就它一个成员,那它大小就是0,那不方便我们进行后面的操作。同样对于我们柔性数组来说,它的内存占用也是用我们的malloc来申请,它申请的时候不和我们上面申请的时候是一样的,它需要先将我们结构体内其他成员的空间先跨过,才是自己的。

type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));

柔性数组的优点

方便内存释放

当里面的成员不是柔性数组而是指针的时候,在使用的过程中,我们对其内部进行了二次的内存分配,而且把整个结构体的指针返回去了,别人使用这个结构体指针,他并不知道里面进行了二次的内存分配,他直接用free释放了整个结构体,不知道要对内部进行free,但是要是柔性数组,就没有这个问题,free一次就行了。

提高我们的访问速度

因为我们申请下来的空间是一片连续的空间,是更加有利于访问的。

总结

动态内存大大的提高了对内存空间的利用,避免了一些不必要的内存浪费。

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

封心锁爱的前夫哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值