如何将两个灵活的数组放在一个结构中?

时间:2019-02-21 21:43:40

标签: c arrays flexible-array-member

我是编程和结构学习的新手,当试图将两个灵活的数组放入单个结构时,它们给我一个错误,为什么我不能将两个数组放入单个结构?我创建了一个神奇宝贝示例来测试struct中的数组,但是只有* pokemon_name []有效,为什么?

#include <stdio.h>

void main()
{
  struct pokemon
  {
    int first_generation;
    char *pokemon_type[];
    char *pokemon_name[];
  } number_pokedex[438];

  number_pokedex[23].pokemon_name[5] = "Arbok";
  number_pokedex[23].pokemon_type[6] = "Poison";
  number_pokedex[23].first_generation = 1;

  printf("Name of the pokemon: %s\n", number_pokedex[23].pokemon_name[5]);
  printf("Type of the pokemon: %s\n", number_pokedex[23].pokemon_type[6]);
  printf("From first generation?: %d\n", number_pokedex[23].first_generation);
}

2 个答案:

答案 0 :(得分:1)

为什么会显示错误消息?

C标准在6.7.2.1 / 18部分中说:

  

作为特殊情况,结构的最后一个元素具有多个   命名成员可能具有不完整的数组类型;   灵活的数组成员。在大多数情况下,灵活数组成员   被忽略。特别是,结构的大小就像   柔性数组成员被省略,除了它可能有更多   比遗漏所暗示的尾随填充。

在您的情况下,您有一个flexible array,它不是结构的最后一个元素,因此不是错误。

为什么C不允许多个弹性数组成员?

定义具有柔性数组的结构的行为,以便它可以像在结构代码之后 之后启动柔性数组一样工作。

 +--------------------------------+----+----+----+----+
 | struct without flexible array  |f[0]|f[1]|f[2]|... |
 +--------------------------------+----+----+----+----+

因此您可以编写如下代码:

  struct test
  {
    int a;
    int flex[];
  } *pt, array[10];

  static struct test t={ 1, {2,3,4}};
  printf ("%x %x %x\n", &t, &t.flex[0], &t.flex[3]);

  pt = malloc(sizeof(struct test)+20*sizeof(int)); 
  printf ("%x %x\n", pt, &pt->flex[0]);

问题是您必须知道为灵活数组保留了多少个元素(静态保留或动态分配)。如果C允许多个柔性数组,则这种行为将不再可能,因为编译器将不知道第二个柔性数组将从何处开始。

替代

现在,您可以通过使用更健壮的固定大小数组或通过指向指针的方式使用动态数组来很好地重写代码。

struct pokemon
{
  int first_generation;
  char **pokemon_type;
  char **pokemon_name;
} number_pokedex[438];

在这种情况下,您必须通过分配足够大小的数组来初始化char**指针:

// assuming that no more than 10 elements in item 23.  
number_pokedex[23].pokemon_name = calloc (10, sizeof(char*));
number_pokedex[23].pokemon_type = calloc (10, sizeof(char*));

您还需要在不再需要时释放阵列。最后,在复制结构元素时,您必须格外小心,因为您将克隆指针。

答案 1 :(得分:1)

尽管Christophe提供了一个非常合理的传统答案,但您可能想知道一个替代方法。如果您希望限制名称的长度,则可以使用数组数组代替指针数组。

typedef char name_type[20];

struct pokemon
{
  int first_generation;
  name_type *pokemon_type, *pokemon_name;
} number_pokedex[438];

void b() {
  number_pokedex[23].pokemon_name = calloc (10, sizeof(name_type));
  number_pokedex[23].pokemon_type = calloc (10, sizeof(name_type));
}

这表示您的名称为20个字节,而数组为200个字节:10个元素,每个20个字节。与指针数组技术不同,这里的calloc不是分配指针,而是分配数组,因此您只有一个分配和一个释放。

IMO数组数组更易于使用:当需要填充名称时,已经分配了存储空间,而当需要释放数组时,则不必为每个元素追逐指针。

一个普遍的反对意见是,该技术要求在编译时确定名称大小,从而使其“灵活性”降低。不过,这似乎没有什么大问题,因为无论名称出现在哪里,隐含的限制都是它是GUI中的字段还是数据库中的列,终端的宽度还是窗口的大小。信封。还可以决定您的名字有多大,然后继续下去。