Как хранить данные в массивах переменной длины, не вызывая повреждения памяти? - PullRequest
2 голосов
/ 11 декабря 2008

Это довольно простой вопрос, который по какой-то причине надлежащего решения ускользает от меня в данный момент. Я имею дело со сторонним SDK, который объявляет следующую структуру:

struct VstEvents
{
    VstInt32 numEvents;  ///< number of Events in array
    VstIntPtr reserved;  ///< zero (Reserved for future use)
    VstEvent* events[2]; ///< event pointer array, variable size
};

Несмотря на то, что это массив «переменного размера», он объявляется статически. Очевидно, что если я сделаю объект VstEvents, установлю numEvents на что-то, а затем пройду и начну добавлять их в массив, это вызовет повреждение памяти.

Так, как я должен должным образом иметь дело с такой структурой? Должен ли я выделить свой собственный массив VstEvent *, а затем указать ему события [0]?

Ответы [ 4 ]

4 голосов
/ 11 декабря 2008

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

struct VstEvents
{
    VstInt32 numEvents;  ///< number of Events in array
    VstIntPtr reserved;  ///< zero (Reserved for future use)
    VstEvent* events[2]; ///< event pointer array, variable size
};

#define numEventsRequired 10
VstEvents *vstEvents = (VstEvents*)malloc(sizeof(VstEvents) + sizeof(VstEvent*)*(numEventsRequired-2));

vstEvents->numEvents = numEventsRequired;
1 голос
/ 11 декабря 2008

Если вы знаете, сколько их, вы можете выделить их с помощью

struct VstEvents *evnts;

evnts = (struct VstEvents*)malloc(sizeof(struct VstEvents) + 
                                  numEvents*sizeof(VstEvent*));

Это выделит 2 дополнительных слотов

0 голосов
/ 13 декабря 2008

Ваша сторонняя библиотека немного странная. Необходимо различать два вида «массивов переменного размера»

  • Размер известен, когда массив выделен , и после этого он никогда не изменяется . Это простой случай, и ниже я показываю идиому C99.

  • Возможный размер неизвестен, когда массиву выделяется и массив может нуждаться в увеличении в течение своего времени жизни. Для чего-то подобного я бы порекомендовал вам проверить реализацию Seq_T в исходном файле seq.c в C-интерфейсах и реализациях Дэйва Хансона . Вы можете легко адаптировать его код.

Если вы знаете размер во время выделения, идиома C99 такова:

struct VstEvents
{
    VstInt32 numEvents;  ///< number of Events in array
    VstIntPtr reserved;  ///< zero (Reserved for future use)
    VstEvent* events[];  ///< event pointer array, variable size
};


struct VstEvents *alloc_vst_events(int num_events) {
  struct VstEvents *p = 
            malloc(sizeof(*p) + num_events * sizeof(p->events[0]));
  return p;
}

Ключ в том, что странный массив в структуре с неопределенным размером. Требуется C99.

Так как вы застряли со странной странностью, я бы попробовал это:

#define NELEMS(A) (sizeof(A) / sizeof((A)[0]))

struct VstEvents *alloc_vst_events(int num_events) {
  struct VstEvents *p;
  int events_needed = num_events - NELEMS(p->events);
  p = malloc(sizeof(*p) + events_needed * sizeof(p->events[0]));
  return p;
}

Отказ от ответственности: Я не проталкивал этот код через компилятор . Исправления приветствуются.

0 голосов
/ 11 декабря 2008

Структура объявляет массив (размером 2) указателей на объекты VstEvent. Вы должны выделить VstEvent и назначить его для events [0], установив numEvents равным 1. Если у вас есть 2 VstEvents, затем выделите другое VstEvent, назначьте его для events [1] и установите для numEvents значение 2. Если вам нужно больше 2 , тогда вам нужно будет сделать realloc для VstEvents, чтобы увеличить его размер, чтобы в событиях содержалось нужное количество указателей и присваивалось 2, 3, 4, ... по мере необходимости. Или, если вы заранее знаете, сколько событий вам нужно сохранить, вы можете выделить их изначально, как показывает @ SDX2000.

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

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