Самостоятельные ссылки переменного размера в структуре - PullRequest
0 голосов
/ 22 декабря 2011

Я пытаюсь реализовать что-то, что требует такой структуры:

struct abc
{  
  int size;
  struct abc *links[size];
}

Здесь я хочу, чтобы size изменялось во время выполнения, а не просто отличалось для каждого экземпляра abc,и экземпляры abc имеют различное количество ссылок в зависимости от программы.Как мне создать / управлять / выделить память для такой структуры данных?Это вообще возможно в C?

Ответы [ 5 ]

3 голосов
/ 22 декабря 2011

Стандарт C (C99 и последующие) предусматривает следующую конструкцию для решения такой ситуации, которая называется гибким элементом массива:

struct abc
{  
  size_t size;
  struct abc *links[];
};

Вы бы выделили такого зверя с помощью malloc:

struct abc * a = malloc(sizeof(struct abc) + sizeof(struct abc*[n]));
a.size = n;
for(size_t i = 0; i < n; ++i) a.links[i] = 0;
.
free(a);
3 голосов
/ 22 декабря 2011

Самый простой способ - изменить структуру следующим образом:

struct abc
{  
  int size;
  struct abc **links;
}

и динамически вызывать массив:

abc.links = (struct abc **)calloc(abc.size, sizeof(void *));

Затем вы можете обращаться к элементам массива ссылок таким образом:

struct abc a,b,c, ...;
int n;
...
a.links = (struct abc **)calloc(a.size, sizeof(void *);
a.links[n] = &b;
struct abc *z = a.links[n];

Будьте осторожны, не пытайтесь получить доступ к элементам за пределами массива calloc, иначе вы получите исключения из памяти и непредвиденное поведение.Не забудьте также освободить (abc.links) для каждой выделенной структуры, чтобы предотвратить утечки памяти ...

Надеюсь, это поможет

1 голос
/ 22 декабря 2011

Вы можете сделать это, но это не автоматически. Я бы сделал это с помощью некоторой процедуры инициализации:

struct *abc abc_init(int size)
{
    struct abc *abc = calloc(1, sizeof(*abc));
    abc->size = size;
    abc->links = calloc(1, sizeof(*(abc->links)) * size);

    return abc;
}

Тогда у вас также может быть бесплатная процедура:

void abc_free(struct abc *abc)
{
    for (int i = 0; i < abc->size; i++) {
        abc_free(abc->links[i]);
    }
    free(abc->links);
    free(abc);
}

Обратите внимание, что abc_free() вызывает себя для каждого элемента в links в этом примере, поэтому вы должны посмотреть нашу рекурсию здесь. Также обратите внимание, что для компактности здесь отсутствует вся проверка на ошибки (например, проверка на NULL).

Эти процедуры упрощают создание и освобождение ваших структур, тогда все, что вам нужно сделать, - это получить доступ / установить их.

0 голосов
/ 22 декабря 2011

Есть люди, которые напишут это:

struct abc
{  
  size_t size;
  struct abc *links[1];
};

struct abc* abc_create(size_t size)
{
   struct abc* abc = calloc(1, sizeof(struct abc) + (size - 1) * sizeof(struct abc*));
   abc->size = size;
   return abc;
 }
0 голосов
/ 22 декабря 2011

Существует возможность, если вы не хотите помнить, чтобы позвонить free(abc.links), и если size не изменится за время существования объекта:

struct abc
{  
    int size;
    struct abc *links[0]; // use 1 if your compiler complains
}

( Примечание. Этот специальный массив нулевой длины должен быть последним членом структуры )

Как может помочь массив нулевой длины? Это работает, если вы выделите abc с

 struct abc * a = malloc(sizeof(abc)+ size * sizeof(struct abc *));

Это намеренно создает слишком много памяти, чтобы мы могли затем безопасно использовать a-> links [3] или a-> link [4] (при условии, что мы не забываем соблюдать size. Затем мы можем просто использовать free(a), нам не нужно (и мы не можем) free(a->links);.

В любом случае, не забудьте освободить каждый из a->links[0] и a->links[1] и т. Д. До a->links[a->size - 1], прежде чем пытаться освободить a.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...