柔性数组,你喜不喜欢?

古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。                      ——苏轼

 

目录

一.什么是柔性数组?

二.柔性数组的特点

三.柔性数组的使用

四.柔性数组的优势 


一.什么是柔性数组?

也许你从来没有听说过柔性数组,但是它确实存在。
在C99中,结构体中最后一个元素允许是未知大小的数组。这就叫柔性数组成员。

如何理解呢?接下来我们使用代码来理解一下柔性数组。

struct s
{
	int n;
	char c;
	int arr[];//或者写成int arr[0]
	//这就是柔性数组成员
};

这里数组的大小是未知的,并且必须是最后一个元素。这里我们就要引出柔性数组的特点了。

二.柔性数组的特点

柔性数组的特点:

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

关于柔性数组特点的理解:

理解1.结构体中柔性数组成员前面必须至少有一个其他成员。

也就是结构体中不能只存在柔性数组成员,而没有其他结构体成员。这样写是不可以的,结构体成员是柔性数组,大小是未知的所以内存都不知道如何给结构体开辟大小。

struct s
{
	int arr[];
};

理解2.sizeof返回的这个结构体的大小不包括柔性数组的内存。

就是当我们在使用sizeof计算结构体的大小时,计算出来的大小时不包括柔性数组成员的大小的。

struct s
{
	int n;
	char c;
	int arr[];
};
int main()
{
	printf("%d\n", sizeof(struct s));
	return 0;
}

我们之前学习了内存对齐,很容易得知,int和char所求出来的结构体大小就是8个字节。
这跟柔性数组是没有关系的,所以说内存是不会对柔性数组开辟空间的。

理解3.包含柔性数组成员的结构体用malloc函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小。

这是正常的开辟结构体:

struct s
{
	int n;
	char c;
};
int main()
{
	struct s ss = { 0 };
	return 0;
}

但是柔性数组的大小未知,我们就不能像这样开辟结构体。
如果要开辟结构体,我们就要使用malloc函数来开辟结构体。

struct s
{
	int n;
	char c;
	int arr[];
};
int main()
{
	struct s*ps=(struct s*)realloc(sizeof(struct s) + 10 * sizeof(int));
	//这里sizeof(struct s)是为int和char开辟的8个字节
	//而10 * sizeof(int)这就是为柔性数组动态开辟的40个字节
	return 0;
}

使用了malloc函数开辟了柔性数组,我们就可以使用柔性数组了。

三.柔性数组的使用

上面我们使用malloc对柔性数组开辟了40个字节,我们就可以给赋值10个值,然后给它打印出来。

#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
struct s
{
	int n;
	char c;
	int arr[];
};
int main()
{
	//开辟空间
	struct s*ps=(struct s*)malloc(sizeof(struct s) + 10 * sizeof(int));
	if (ps == NULL)
	{
		printf("%s\n", strerror(errno));
		return 1;
	}
	ps->n = 100;
	ps->c = 'a';
	//使用
	printf("%d %c\n", ps->n, ps->c);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//释放
	free(ps);
	ps = NULL;
	return 0;
}

当我们还想对柔性数组使用时,我们还可以使用realloc再次扩大内存,这样就可以使用了。

四.柔性数组的优势 

我们之前学习了通讯录和顺序表,结构体成员还可以使用指针,这样也可以动态开辟空间。
这里我们就使用指针来实现上述柔性数组一样的功能来对比一下柔性数组到底有什么不一样。

struct s
{
	int a;
	char c;
	int* arr;
};

struct s
{
	int a;
	char c;
	int* arr;
};
int main()
{
	struct s* ps = (struct s*)malloc(sizeof(struct s));//这里是开辟的一个结构体的大小
	if (ps == NULL)
	{
		perror("malloc");//同样是打印错误的信息
		return 1;
	}
	struct s* ptr = (struct s*)malloc(sizeof(int) * 10);//给arr开辟空间
	if (ptr == NULL)
	{
		perror("malloc");
		return 1;
	}
	else
	{
		ps->arr = ptr; 
	}
	ps->a = 10;
	ps->c = 'a';
	printf("%d %c\n", ps->a, ps->c);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		ps->arr[i] = i + 1;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	free(ps->arr);//这里我们必须先释放arr
	ps->arr = NULL;
	free(ps);//再释放ps
	ps = NULL;
	return 0;
}

在实现相同的功能的时候,柔性数组需要malloc一次,free一次。而结构体指针需要malloc两次,free两次。

柔性数组的优点:

第一个好处是:方便内存释放。
第二个好处是:这样有利于访问速度。

就是malloc次数越多,内存可能不是连续开辟的,开辟的越多,内存中间的空隙越多,也就是我们说的内存碎片。所以柔性数组相较于结构体指针来说,可以减少内存碎片,从而提高访问速度。

malloc次数越少,连续内存越多,连续的内存有益于提高访问速度,也有益于减少内存碎片。

猜你喜欢

转载自blog.csdn.net/adcxhw/article/details/129835593