先说c++吧
typedef struct _node {
int num;
int age[];
}node;
这个就是所谓的柔性数组。结构中最后一个元素允许是未知大小的数组。(必须是最后一个,这很重要,下面解释)
可以试一下,sizeof(node)是4,若将num去掉,sizeof(node)就是1,我们知道空的struct,sizeof是1。有此可发现,柔性数组并不占有空间,这是为了动态的储存,后续可扩大空间。需要注意的是,结构中的柔性数组前面必须至少一个其他成员,柔性数组成员允许结构中包含一个大小可变的数组,sizeof返回的这种结构大小不包括柔性数组的内存。包含柔数组成员的结构用malloc函数进行内存的动态分配,且分配的内存应该大于结构的大小以适应柔性数组的预期大小。
如果改成c语言,c语言不允许空struct,而只有一个柔性数组的空结构体,sizeof是4。这个是因为编译器的规定。我用的是gcc和g++。
如果将例子中的age[]改为age[0]也是可以的,虽然意义有点不一样。
还有一点,这种变长的数组例如age[]或者说写age[0]这种,在结构体外是不允许的。我的想法是,因为struct是本身就占用空间的,分配了地址的。因此在struct里的变长数组是有一个索引的,也就是在系统中有归属。而struct外的普通数组,如果写成name[]或者name[0],那么系统不知道去哪里寻找数组,没法定义。所以不允许。换个思路,age[]这样其实就相当于声明了一个指针char* name。而这个指针没有分配空间,自然也是不行的。虽然出错的环节不一样,但我想还是可以类比下的。
然后说回前面说的,柔性数组必须是结构中最后的元素。这个是因为,如果申请一定长度的空间,比如说这个例子,有10个age。
node* tmp = (node*)malloc(sizeof(node) + 10*sizeof(int));
可以发现,是在malloc时候申请了10个int的大小,这个空间储存储存10个age。这10个地址和node本身是malloc一起申请的,所以是连着的。因此,如果不是最后面的,空间就混乱了,放在最后面才能处理嘛。
当然那些就是个讨论,现在不重要,知道咋搞就行了。还是看个柔性数组的使用吧。
假设有一个小组,现在需要输入每个的名字和年龄。而这个结构体是需要复用的啊,预先声明的太大也不好,这个时候这柔性数组就有用了。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _Info {
char name[10];
int age;
}Info;
typedef struct _Group {
int num;
int counter;
Info staff[];
}Group;
int main() {
int Len = 10;
int Size = sizeof(Group) + Len * sizeof(Info);
Group* org = (Group*)malloc(Size);
memset(org, 0, Size);
org->num = Len;
for (int i = 0; i < org->num; i++) {
org->counter++;
org->staff[i].age = i + 1;
strcpy(org->staff[i].name, "zhangsan");
}
for (int j = 0; j < org->counter; j++)
printf("name is %s, age is %d\n", org->staff[j].name, org->staff[j].age);
return 0;
}
我在结构体Group里多加了个counter,我是想到有这种情况可以用,就是一次建立20个Info的空间,在添加时候,counter计数发现要到20个了,这时候可以realloc一下,这就和c++ vector一样用了。
具体情况具体说吧,总归这个柔性数组还是有用的。