【C语言】柔性数组/变长数组

文章目录

1.柔性数组的概念

2.柔性数组的使用和特点

1.柔性数组不占用内存空间

2.有柔性数组的结构要用malloc分配空间

3.柔性数组的优势

1.方便内存释放

2.提高访问速度、减少内存碎片


1.柔性数组的概念

C99标准下结构中最后一个元素允许是未知大小的数组 ,这个数组就是柔性数组,也被称作变长数组。

        这里必须注意三点:第一,在结构体中定义的未知大小数组。 第二,该位置大小数组必须是结构体最后一个元素,该数组前面至少有一个元素。 举个例子,比如下方图片,arr就是柔性数组。 第三,数组名永远不会是指针,但是对于这个数组的大小,我们可以动态分配(下面会体现出来)。

2.柔性数组的使用和特点

1.柔性数组不占用内存空间

        对于编译器来说,柔性数组并不占用内存空间,可以用sizeof来验证。如下代码,运行后结果如图,是8,说明struct s这个结构体大小为8,而int类型和float类型的数据都是4个字节,根据结构体内存对齐规则,如果不计算arr的大小,结构体大小确实为8。

#include<stdio.h>
#include<stdlib.h>

struct S
{
	int a;
	float b;
	int arr[];
};


int main()
{
	printf("%d ", sizeof(struct S));
}

2.有柔性数组的结构要用malloc分配空间

         包含柔性数组成员的结构要用malloc分配空间,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。如下,malloc分配给了s原本结构体的大小和4个int类型数据的大小,这4个int类型数据的大小就是分配给arr的,此时arr可用的是arr[0]到arr[3]。

        与此同时,由于是malloc分配,所以最后不用的时候要free掉。

#include<stdio.h>
#include<stdlib.h>

struct S
{
	int a;
	float b;
	int arr[];//结构体最后一个元素允许是大小未知的,但是其前面至少有一个成员
};

int main()
{

	//开辟
	struct S* s = (struct S*)malloc(sizeof(struct S) + sizeof(int) * 4);
	if (!s)
	{
		printf("malloc fail!");
		exit(-1);
	}

	//使用
	s->a = 10;
	s->b = 5.5;
	for (int i = 0;i < 4;i++)
		s->arr[i] = i+1;

	printf("%d  %.2f\n", s->a,s->b);
	for (int i = 0;i < 4;i++)
	{
		printf("%d ", s->arr[i]);
	}

	//释放
	free(s);
	return 0;
}

        既然是“柔性数组”,那么其“”体现在哪里呢?比如上面的代码,arr只可以存放4个数据,但是现在需要存放10个数据,那么就要arr数组可以扩大容量,而柔性数组可以实现这个功能,其“柔”体现在这里。比如下面代码,调整的代码块,用realloc分配了s原本结构体的大小和10个int类型数据的大小,此时arr数组就可以存储10个数据。对新开辟的空间赋值,其运行结果如下图。

#include<stdio.h>
#include<stdlib.h>

struct S
{
	int a;
	float b;
	int arr[];//结构体最后一个元素允许是大小未知的,但是其前面至少有一个成员
};


int main()
{
	//开辟
	struct S* s = (struct S*)malloc(sizeof(struct S) + sizeof(int) * 4);
	if (!s)
	{
		printf("malloc fail!");
		exit(-1);
	}

	//使用
	s->a = 10;
	s->b = 5.5;
	for (int i = 0;i < 4;i++)
		s->arr[i] = i+1;

	printf("%d  %.2f\n", s->a,s->b);
	for (int i = 0;i < 4;i++)
	{
		printf("%d ", s->arr[i]);
	}


	//调整
	struct S* ptr = (struct S*)realloc(s, sizeof(struct S) + 10 * sizeof(int));
	if (!ptr)
	{
		printf("realloc fail!");
		exit(-1);
	}
	else
	{
		s = ptr;
	}

	//使用
	for (int i = 4;i < 10;i++)
	{
		s->arr[i] = i+1;
	}
	for (int i = 4;i < 10;i++)
	{
		printf("%d ", s->arr[i]);
	}
	//释放
	free(s);
	return 0;
}

3.柔性数组的优势

        到这里,不免会有疑问,既然柔性数组是为了让数组容量可以变化,那么为什么不直接定义一个指针,然后动态分配内存呢?实际上,柔性数组比使用指针动态分配内存要好,一方面方便内存的释放,另一方面可以提高访问速度、减少内存碎片

1.方便内存释放

        如下代码,在开辟内存的时候,一方面要开辟结构体的空间(这里是为了模仿柔性数组,所以结构体也动态开辟),另一方面要开辟arr指向的数组的空间。释放的时候,既要释放结构体空间,又要释放arr指向数组的空间,比较麻烦。而上文中,使用柔性数组,可以直接一次性开辟、一次性释放,相较之下很方便。

#include<stdio.h>
#include<stdlib.h>

struct S
{
	int a;
	float b;
	int* arr;
};

int main()
{
	//开辟
	struct S*  s = (struct S*)malloc(sizeof(struct S));
	if (!s)
	{
		printf("malloc fail!");
		exit(-1);
	}

	int* ptr = (int*)malloc(sizeof(int) * 10);
	if (!ptr)
	{
		printf("malloc fail!");
		exit(-1);
	}
	s->arr = ptr;

	//使用
	s->a = 10;
	s->b = 5.5;
	for (int i = 0;i < 10;i++)
	{
		s->arr[i] = i + 1;
	}

	printf("%d %.2f\n", s->a, s->b);

	for (int i = 0;i < 10;i++)
	{
		printf("%d ", s->arr[i]);
	}

	//释放
	free(s);
	s = NULL;
	free(ptr);
	ptr = NULL;

	return 0;
}

2.提高访问速度、减少内存碎片

         如下图,左边是结构体的内存示意,右边是堆区内存示意图。结合上面代码,在堆区内存中,开辟了一块空间存放结构体s,同时还要开辟另一块空间存放数组arr,但是这块空间位置随机的,可能是蓝色方框1、2、3、4中任意一个,也可能是其他地方,它和结构体并不连续,就导致结构体和数组arr中间的那一块空间,很难被利用,这块空间就被称为内存碎片

        但是用柔性数组就不胡有这样的问题,柔性数组 开辟的arr就是一个数组,而不是指针,如下图,这样不会存在内存碎片的问题。同时,由于数组就在结构体里面,所以a、b、arr数组在内存里是连续的,访问起来要快一些。而像上面的,arr是指针,多了一个找到arr物理地址的过程,相较之下要慢一点点。

 

         关于柔性数组,就介绍这么多啦!!!

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力努力再努力.xx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值