如何在C中使用灵活数组来保存多个值?

我有以下代码:

typedef struct { int name; int info[1]; } Data; 

那我有五个变量:

 int a, b, c, d, e; 

我怎样才能将它作为一个灵活的数组来保存五个变量的所有值?

要正确执行此操作,您应该将灵活数组成员声明为不完整类型:

 typedef struct { int name; int info[]; } Data; 

然后动态分配内存

 Data* data = malloc(sizeof(Data) + sizeof(int[N])); for(int i=0; iinfo[i] = something; // now use it just as any other array } 

编辑

确保您使用C99编译器才能工作,否则您将遇到各种问题:

如果你分配一个长度为1的数组,那么你将malloc 1项作为数组的第一个元素和struct,然后在那之后追加N个字节。 这意味着您实际上正在分配N+1个字节。 这可能不是人们想要做的事情,它使事情变得不必要地复杂化。

(为了解决上述问题,GCC有一个允许零长度数组的C99前扩展,这在标准C中是不允许的。)

在C99之前,或者在作为灵活数组成员的任何其他上下文中,C不允许不完整的数组类型,如我的代码中所示。

C99保证在使用灵活的arrays成员时您的程序是明确定义的。 如果不使用C99,则编译器可能会在其他结构成员和最后一个数组之间附加“struct padding”字节。 这意味着data->info[0]可以指向struct padding字节,而不是指向已分配数组中的第一项。 这可能会导致各种奇怪的,意外的行为。

这就是为什么灵活的数组成员在C99之前被称为“struct hack”的原因。 他们不可靠,只是一个可能或可能不起作用的肮脏黑客。

这种结构在C语言中是一种常见的习语; 我们的想法是在struct的末尾分配额外的空间,其中第一个实际存储后的info元素。 然后, struct末尾的size-1数组成员允许您使用数组语法来访问此数据。

如果要存储5个元素,则需要执行以下操作:

 Data * data=malloc(sizeof(Data)+sizeof(int)*4); /* 4 because the first element is already included in the size of the struct */ /* error checking omitted ... */ data->info[0]=a; data->info[1]=b; data->info[2]=c; data->info[3]=d; data->info[4]=e; /* ... */ /* when you don't need d anymore remember to deallocate */ free(data); 

您也可以编写辅助函数来简化分配:

 Data * AllocateData(size_t elements) { if(elements==0) return NULL; return malloc(sizeof(Data)+sizeof(int)*(elements-1)); } 

而上面的例子将是

 Data * data=AllocateData(5); /* then as above */ 

这称为灵活arrays,在C99中引入。 通常也称为struct hack 。 在C99中,应声明灵活数组成员的大小。

您需要动态分配可以容纳比结构大小更多内存的内存。 由于数组是结构中的最后一个成员,只要为其分配了足够的内存,就可以将其索引超过其大小。

  typedef struct { int name; int info[1]; } Data; Data *d = malloc(sizeof(*d) + (5 * sizeof(int)); //enough for the struct and 5 more ints. //we have enough room for 6 elements in the info array now //since the struct has room for 1 element, and we allocated room for another 5 ints d->info[0] = 1; d->info[1] = 2; d->info[2] = 3; d->info[3] = 4; d->info[4] = 5; d->info[5] = 6; 

使用1 size int info[1];的数组成员int info[1]; 以这种方式是技术上未定义的行为 – 但在许多流行的编译器上都能正常工作。 使用C99编译器,这由声明为int info[];的灵活数组成员支持int info[]; 。 在这里阅读更多