Как я могу поместить два гибких массива в одну структуру? - PullRequest
0 голосов
/ 22 февраля 2019

Я новичок в программировании и изучении структуры. Когда я пытаюсь поместить два гибких массива в одну структуру, они выдают ошибку, почему я не могу поместить два массива в одну структуру?Я создал пример покемона для тестирования массива в структуре, но работает только * 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 голосов
/ 22 февраля 2019

В то время как Кристоф дает совершенно здоровый традиционный ответ, вы, возможно, захотите узнать об альтернативе.Вместо массива указателей, если вы хотите ограничить длину имен, вы можете вместо этого использовать массив массивов.

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 массив массивов проще в использовании: когда приходит время для заполнения имени, хранилище уже выделено, а когда приходит время освобождать массив, вам не нужно гоняться за указателемдля каждого элемента.

Распространенным возражением является то, что этот метод требует, чтобы размер имени был установлен во время компиляции, что делает его менее "гибким".Это менее важно, чем может показаться, потому что везде, где появляется имя, подразумевается ограничение, будь то поле в графическом интерфейсе пользователя или столбец в базе данных, ширина терминала или размер окна в окне.конверт.Можете также решить, насколько велики ваши имена, и покончить с этим.

0 голосов
/ 22 февраля 2019

Почему сообщение об ошибке?

Стандарт 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 допустил несколько гибких массивов, такое поведение больше не было бы возможным, так как компилятор не знал бы, где начнется второй гибкий массив.

Alterantive

Теперь вы можете очень хорошо переписать свой код, используя более надежные массивы фиксированного размера или динамические массивы с помощью указателя на указатели.

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*));

Вам также необходимо освободить массивыкогда больше не нужен.Наконец, вам нужно быть особенно осторожным при копировании элементов структуры, так как вы клонируете указатели.

...