Динамически размещать структуру и массив в ней в C - PullRequest
2 голосов
/ 17 декабря 2011
  1. Как я буду динамически выделять массив struct Register, при этом каждый регистр будет иметь динамически размещенный массив struct Field?
  2. Как я получу доступ к каждому из этих членов (Могу ли я использовать Register_A.FieldArray[23].High?)?
  3. Как эффективно инициализировать структуру регистров (при условии, что массив структур регистров большой)?(Как сегмент данных без каких-либо вычислений)

    struct Field
    {
        char    High;                
        char    Low;                
        char    Attribute;
    };
    
    struct Register 
    {
       unsigned int    ResetValue;
       struct Field    FieldArray[];
    };
    

Ответы [ 4 ]

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

Я настоятельно не рекомендую вам использовать гибкий массив, потому что это не что иное, как кладжа. Вместо этого вы должны объявить и использовать его как struct Field *, malloc, увеличивая его размер, как любой другой динамический массив.

Тем не менее, malloc с размером массива n_elem:

struct Register register = malloc(sizeof(*register) + n_elem * sizeof(*register->FieldArray));

Для доступа к элементам:

char high = register->FieldArray[0].High;

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


Почему гибкие массивы не рекомендуется:

Я сошлюсь на этот пост , но я не думаю, что ответ завершен (большая часть разочарования, потому что это только c-99), поэтому я добавлю свои мысли.
Они являются исключением. По сути, вы объявляете массив нулевым размером и каждый раз обращаетесь к нему за пределами, просто в той степени, на которую вы выделили. Вы не можете использовать структуру с гибким массивом, как любая другая структура, например вы не можете взять sizeof гибкий массив. Если вы объявляете статический или массив из них, вы не можете использовать член массива, потому что для него нет выделенного пространства.

Пример использования их в массиве:

#include <stdio.h>

struct test {
        int val;
        int arr[];
};

int main() {
        struct test tarr[2];
        printf("%p\n%p\n", &tarr[0].arr[0], &tarr[1].val);
}

Выход:

0x7fff59b67164
0x7fff59b67164

Они по одному адресу. Если вы попытаетесь записать в элемент массива, вы перезапишете следующий объект. Если вы пытаетесь читать с него, вы читаете данные из следующего объекта. В зависимости от заполнения это может быть даже бессмысленное значение из заполнения.

Они похожи на goto утверждения, оба потенциально полезны, но чаще всего плохая идея. Если вы не знаете, почему они опасны, вам не следует их использовать (в реальном коде; неплохо было бы поиграться с ними в тестовой программе, чтобы увидеть, как их правильно использовать и как они могут представить проблемы).

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

Способ сделать это, изменив размер struct Register:

struct Register 
{
   unsigned int    ResetValue;
   struct Field    FieldArray[1];
};
struct Register *Register_Create()
{
    struct Register *reg = calloc(1, sizeof(struct Register) - sizeof(struct Field));
    // check for NULL pointer
    return reg;
}

struct Register *Register_SetSize(struct Register *reg, size_t size)
{
    // check for NULL
    reg = realloc(reg, sizeof(struct Register) + sizeof(struct Field) * (size - 1));
    // check for NULL
    return reg;
}

Вот пример того, как использовать это:

struct Register *reg = Register_Create();
reg = Register_SetSize(register, 5);
// You now have space for 5 elements in reg->FieldArray
reg->FieldArray[3].High = 'B';

Имейте в виду, что это решение работает, только если FieldArray находится в конце struct.

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

Гибкие члены массива являются частью C99.

  1. Вы можете выделить struc с гибким элементом массива так, как вам кажется: malloc(sizeof(struct Register) + sizeof(struct Field[n])), где n - необходимый размер.Не забудьте инициализировать массив и отследить n, лучше всего выделив для этой цели члена
  2. да

Кстати: malloc выше может бытьпотеря байтов из-за заполнения, но обычно не стоит думать о точной формуле.Минимальный имеет максимум и использует offsetof.

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

Вам нужно знать, насколько велик FieldArray.Если это не исправлено, вам нужно объявить с максимальным значением.Тогда вы можете просто выделить регистр и получить доступ, как вы указали

...