【问题标题】:how to use flexible array in C to keep several values?如何在 C 中使用灵活数组来保留多个值?
【发布时间】:2013-06-27 13:38:33
【问题描述】:

我有以下代码:

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

那么我有五个变量:

int a, b, c, d, e;

如何将它用作一个灵活的数组来保留五个变量的所有值?

【问题讨论】:

  • 这里的灵活是什么意思?
  • 什么是“灵活数组”?您显示的结构根本没有数组。你的问题一点也不清楚。
  • 很明显他的意思是一个灵活的数组成员。如果您不知道那是什么,那么,请不要费心回答。
  • 有些人使用这样的结构并为整个结构分配更多的内存,这样结构和数组将是一个单一的、连续的分配:Data *d = malloc(sizeof(Data) + 10*sizeof(int));
  • @ctn 不仅仅是“某些人”。灵活的数组成员是一种语言特性,它已成为 C 语言 14 年的一部分。即使在 C99 之前,它也很常用(通常称为“struct hack”或类似名称),但当时它是未定义的行为且不安全。

标签: c arrays


【解决方案1】:

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

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 有一个 pre-C99 扩展,允许零长度数组,这在标准 C 中是不允许的。)

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

C99 保证您的程序在使用灵活的数组成员时定义良好。如果您不使用 C99,那么编译器可能会在其他结构成员和最后的数组之间附加“结构填充”字节。这意味着data-&gt;info[0] 可以指向结构填充字节,而不是分配数组中的第一项。这可能会导致各种奇怪的、意外的行为。

这就是为什么在 C99 之前灵活数组成员被称为“struct hack”的原因。它们不可靠,只是一种可能有效也可能无效的肮脏黑客。

【讨论】:

  • 人们有时使用int info[1]的原因是为了避免依赖C99。似乎在这一点上依赖 C99 并不是一个坏主意,但你自己提到了它,所以它似乎仍然是一个问题。更多信息this answer
  • @Caleb 不使用 C99 编译器时会出现很多问题。我会用更多信息更新答案。
【解决方案2】:

这种结构在 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 */

【讨论】:

    【解决方案3】:

    这称为灵活数组,是在 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 的数组成员 int info[1]; 在技术上是未定义的行为 - 但在许多流行的编译器上都可以正常工作。对于 C99 编译器,这是由声明为 int info[]; 的灵活数组成员支持的。阅读更多here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-02
      • 1970-01-01
      相关资源
      最近更新 更多