2

我是编程和学习结构的新手,当试图将两个灵活的数组放在一个结构中时,他们给了我一个错误,为什么我不能把两个数组放在一个结构中?我创建了一个 pokemon 示例来测试 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);
}
4

2 回答 2

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 中的字段还是数据库中的列,还是终端的宽度或窗口的大小信封。不妨决定你的名字有多大,然后继续做下去。

于 2019-02-21T23:47:26.450 回答
1

为什么错误信息?

C 标准在第 6.7.2.1 / 18 节中说:

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

在您的情况下,您有一个如此灵活的数组,它不是结构的最后一个元素,因此是错误的。

为什么 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*));

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

于 2019-02-21T22:16:43.820 回答