C语言柔性数组使用方法、特点及优点

C语言柔性数组使用方法、特点及优点

在C99标准中定义有,结构体中的最后一个元素允许是未知大小的数组,这个数组就叫做柔性数组,所以说柔性数组其实是结构体中的一个数组,“柔性” 指的是该数组的大小可大可小。例如:

struct S
{
	int i;
	int a[];//柔性数组成员,该数组为柔性数组
};

上面的定义是没有问题的,如果使用的编译器在运行上述代码时报错无法编译,可以像如下方式定义:

struct S
{
	int i;
	int a[0];//将数组的大小设为0
};

上述柔性数组的声明只是用来解释什么是柔性数组,真实的开发环境中,要正确的使用柔性数组,下面进行说明。

struct S
{
	int i;
	char a[0];
};

printf("%d\n", sizeof(struct S));
// 打印结果为4

上述例子说明,在计算包含柔性数组的结构体大小时,忽略柔性数组的大小。
结构体中的最后面这个数组是柔性的,如果希望这个空间可变的话,一般情况下采用动态开辟结构体S的空间:

struct S
{
	int i;
	char a[0];
};

struct S* ps = (struct S*)malloc(sizeof(struct S) + 100*sizeof(char));//给柔性数组预留了100*sizeof(char)的空间
struct S* ptr = NULL; 
ps->i = 20;
strcpy(ps->a, "abcdef");
printf("%s\n", ps->a);

// 当预留的空间大小不够时,可以再动态开辟空间
// 注意这里使用的是ps,代表整块空间的地址不可以使用ps->a
ptr = realloc(ps, sizeof(struct S) + 200*sizeof(char));
if(ptr != NULL)
	ps = ptr;

free(ps);
ps = NULL;

这里要做的事是想让柔性数组可大可小,如果把a的位置换成指针,指针指向的空间是动态开辟的,这样不也是可以的么?

struct A
{
	int i;
	char* a;
};

struct B* ps = (struct B*)malloc(sizeof(struct B));
// 此时申请了8个字节大小的空间,将地址交给ps来维护

// 为了让结构体中a维护的空间像维护可大可小的数组一样,可以让a指向一块儿动态开辟的空间
ps->a = (char*)malloc(100*sizeof(char));
ps->i = 20;
strcpy(ps->a, "abcdef");

//空间不够时,再动态申请
char* ptr = NULL;
ptr = realloc(ps->a, 200*sizeof(char)); 
if(ptr != NULL)
	ps->a = ptr;

free(ps->a);
ps-> = NULL;
free(ps);
ps = NULL;
// 这里注意释放的先后顺序

虽然第二种实现方法可以达到和柔性数组同等的效果,但是柔性数组还是有存在的必要的。首先,使用柔性数组开辟的空间是连续的,而使用指针代替的方法申请的两块内存空间是不连续的,此时在内存中由程序员自己来开辟空间时,如果开辟的空间数量较多,会产生大量的内存碎片;其次,使用柔性数组只需要使用一次malloc和一次free,减少程序出错的可能;然后,在内存访问时存在局部性原理,CPU处理的数据来自内存,每次访问寄存器中的数据时百分之八十的概率是上一次访问的数据的周边的数据,因此数据在内存中如果连续存放的话,访问效率会提高。所以综上所述,使用柔性数组还是有很多优势的。

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

你可能感兴趣的:(C/C++)