C语言——柔性数组

柔性数组概念:

这个概念你可能没听说过,但是这个概念确实存在,在C99中,结构体中最后一个成员允许是未知大小的数组,这就叫做【柔性数组】成员。

cpp 复制代码
struct S
{
	char c;
	int i;
	int arr[0];//未知大小的数组 - 柔性数组成员
};

有些编译器可能不支持上面的写法,可以改成:

cpp 复制代码
struct S
{
	char c;//1
	//3
	int i;//4
	int arr[];//未知大小的数组 - 柔性数组成员
};

柔性数组的特点:

结构中的柔性数组成员前面必须至少有一个其他成员
sizeof返回这种结构体大小不包括柔性数组成员的内存
包含柔性数组成员的结构用malloc进行内存分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

我们还是以刚刚上面的结构体为例:

根据内存对齐规则,这个结构如果不算柔性数组大小的话,的确是8,而我们可以看到,这里打印出来的也确实是8,所以我们可以理解第二条特点sizeof返回结构大小的时候不包括柔性数组的大小。

那么第一条特点也就可以解释了,倘若结构里面只有柔性数组的话,那么sizeof计算结构体大小,就没办法算了,所以结构里柔性数组的前面必须至少有一个其他类型的成员。

那么第三条特点的意思是,我们在为其开辟内存的时候是这样的:

我们定义一个结构变量指针用来接收,然后malloc出来的空间首先sizeof(struct S)代表先给char和int两个成员变量开辟空间,然后剩下的+20就是给柔性数组来开辟的,内存申请的不够了,就可以用realloc重新调整大小。

具体的代码实现是这样的:

cpp 复制代码
struct S
{
	char c;//1
	//3
	int i;//4
	int arr[];//未知大小的数组 - 柔性数组成员
};

int main(){
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 20);
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}
	ps->c = 'w';
	ps->i = 100;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
	}
	//打印
	for (i = 0; i < 5; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//空间不够了
	struct S* ptr = (struct S*)realloc(ps, sizeof(struct S)+40);
	if (ptr != NULL)
	{
		ps = ptr;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	//增容成功后,继续使用
	
	//释放
	free(ps);
	ps = NULL;

	return 0;
}

上面的例子就是对结构里有柔性数组的该如何进行调整,malloc以及realloc,还有即使打印使用的时候。

但是如果我们在柔性数组那里换成指针是不是也一样可以达到空间的可大可小的效果呢?

例如这样的代码:

cpp 复制代码
struct s
{
	char c;
	int i;
	int* data;
};


int main()
{
	struct s* ps = (struct s*)malloc(sizeof(struct s));
	if (ps == NULL)
	{
		perror("malloc1");
		return 1;
	}
	ps->c = 'w';
	ps->i = 100;
	ps->data = (int*)malloc(20);
	if (ps->data == NULL)
	{
		perror("malloc2");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->data[i] = i;
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d ", ps->data[i]);
	}
	//空间不够了,增容
	int* ptr = (int*)realloc(ps->data, 40);
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	else
	{
		ps->data = ptr;
	}
	/*增容成功就使用
	...
	释放*/
	free(ps->data);
	ps->data = NULL;
	free(ps);
	ps = NULL;

	return 0;
}

我们这里结构里放了一个指针变量成员int* data,而我们再用malloc函数申请空间并让data指向这个空间也就达到了和柔性数组一样的效果。只不过我们这里需要malloc两次:

当然也需要释放两次:


那么既然这两个代码实现的效果一样,那么哪个更好一点呢?🤔🤔🤔

答案是:第一个会更好一点。(带有柔性数组)

好处1:方便内存释放

第一个只用申请一次,而第二个则需要申请两次。

好处2:有利于访问速度

一次申请空间,空间内存一定是连续的,但是两次申请空间的话,就不一定是连续的了,内存之间就有可能存在缝隙,那么这些缝隙,也就有可能影响访问速度。(但我个人觉得其实也没多高)。

相关推荐
会员源码网10 小时前
使用`mysql_*`废弃函数(PHP7+完全移除,导致代码无法运行)
后端·算法
木心月转码ing11 小时前
Hot100-Day10-T438T438找到字符串中所有字母异位词
算法
HelloReader12 小时前
Wi-Fi CSI 感知技术用无线信号“看见“室内的人
算法
颜酱14 小时前
二叉树分解问题思路解题模式
javascript·后端·算法
qianpeng89716 小时前
水声匹配场定位原理及实验
算法
董董灿是个攻城狮1 天前
AI视觉连载8:传统 CV 之边缘检测
算法
RuoZoe1 天前
重塑WPF辉煌?基于DirectX 12的现代.NET UI框架Jalium
c语言
AI软著研究员1 天前
程序员必看:软著不是“面子工程”,是代码的“法律保险”
算法
FunnySaltyFish1 天前
什么?Compose 把 GapBuffer 换成了 LinkBuffer?
算法·kotlin·android jetpack
颜酱1 天前
理解二叉树最近公共祖先(LCA):从基础到变种解析
javascript·后端·算法