我有以下代码:
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; i<N; i++)
{
data->info[i] = something; // now use it just as any other array
}
编辑
确保您使用的是 C99 编译器,否则您将遇到各种问题:
如果你分配一个长度为 1 的数组,那么你将 malloc 1 项用于数组的第一个元素和结构,然后在之后追加N
字节。这意味着您实际上是在分配N+1
字节。这可能不是一个人打算做的,它使事情变得不必要地复杂。
(为了解决上述问题,GCC 有一个 C99 之前的扩展,它允许零长度数组,这在标准 C 中是不允许的。)
在 C99 之前,或者在任何其他上下文中,除了作为灵活的数组成员之外,C 不允许像我的代码中所示的那样不完整的数组类型。
C99 保证您的程序在使用灵活的数组成员时是良好定义的。如果您不使用 C99,那么编译器可能会在最后的其他结构成员和数组之间附加“结构填充”字节。这意味着它data->info[0]
可能指向结构填充字节,而不是分配数组中的第一项。这可能会导致各种奇怪的、意外的行为。
这就是为什么在 C99 之前灵活的数组成员被称为“struct hack”的原因。他们不可靠,只是一个肮脏的黑客可能会或可能不会工作。
这种结构在 C 语言中是一个比较常见的习惯用法。这个想法是您在 的末尾分配额外的空间struct
,其中第一个info
之后的元素实际存储在其中。then末尾的 size-1 数组成员struct
允许您使用数组语法来访问此数据。
如果你想存储 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 */
这称为灵活数组,是在 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;
int info[1];
以这种方式使用大小为 1 的数组成员在技术上是未定义的行为 - 但在许多流行的编译器上都可以正常工作。对于 C99 编译器,这是由声明为int info[];
. 在这里阅读更多