Динамично выделите структуру C?

Я хочу динамично выделить структуру C:

typedef struct {
    short *offset;
    char *values;
} swc;

Оба 'смещения' и 'значения', как предполагается, являются массивами, но их размер неизвестен до времени выполнения.

Как я могу динамично выделить память для своей структуры и массивов структуры?

7
задан pf. 30 December 2009 в 12:12
поделиться

13 ответов

swc* a = malloc(sizeof(*a));
a->offset = calloc(n, sizeof(*(a->offset)));
a->values = calloc(n, sizeof(*(a->values)));

Вы не должны бросать void* в c... в c++ вы должны!

2
ответ дан 6 December 2019 в 04:52
поделиться
swc *a = (swc*)malloc(sizeof(swc));
a->offset = (short*)malloc(sizeof(short)*n);
a->values = (char*)malloc(sizeof(char)*n);

Где n = количество элементов в каждом массиве и a - адрес вновь выделенной структуры данных. Не забудьте free() смещения и значения перед free()'ing a

.
19
ответ дан 6 December 2019 в 04:52
поделиться

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

    typedef struct { 
    short *offset; 
    char *values; 
} swc;

swc* createStructure(int Count1, int Count2) { 
  swc *s1 = new swc(); 
  s1->offset = new short[Count1]; 
  s1->values = new char[Count2]; 
  return s1; 
} 

int _tmain(int argc, _TCHAR* argv[])
{
    swc *mystruct;
    mystruct = createStructure(11, 11);

    delete[] mystruct->offset;
    delete[] mystruct->values;
     delete mystruct;
    return 0;
}
0
ответ дан 6 December 2019 в 04:52
поделиться

Вы хотите использовать malloc для выделения памяти, а также, возможно, sizeof() для выделения правильного количества пространства.

Что-то вроде:
structVariable = (*swc) malloc(sizeof(swc));

Should do the trick.

0
ответ дан 6 December 2019 в 04:52
поделиться

Большинство ответов верны. Я хотел бы добавить кое-что, что вы явно не спрашивали, но может быть важным.

Массивы C / C++ не хранят свой размер в памяти . Таким образом, если Вы не хотите, чтобы значения смещения и значения имели значения, определенные во время компиляции (и в этом случае лучше использовать массивы фиксированного размера), Вы можете захотеть хранить размеры обоих массивов в struct.

typedef struct tagswc {
    short  *offset;
    char   *values;
    // EDIT: Changed int to size_t, thanks Chris Lutz!
    size_t offset_count;
    size_t values_count; // You don't need this one if values is a C string.
} swc;

DISCLAIMER: Возможно, я ошибаюсь. Например, если все смещения из всех swc экземпляров имеют одинаковый размер, то лучше сохранить offset_count как глобальный член, а не как член struct. То же самое можно сказать и о значениях и значениях_счета . Также, если значения - это строка на языке C, вам не нужно хранить ее размер, но остерегайтесь Шлемеля-художника - подобных проблем.

.
1
ответ дан 6 December 2019 в 04:52
поделиться

Использовать функцию malloc или calloc для динамического выделения памяти . и выполнить поиск в Google для получения примеров.

The calloc function initializes allocated memory to zero.
1
ответ дан 6 December 2019 в 04:52
поделиться

Здесь нужно добавить к множеству правильных ответов одну вещь: вы можете malloc использовать структуру увеличенного размера для размещения массива переменного размера в последнем члене.

struct foo {
   short* offset;
   char values[0]
};

и позже

struct *foo foo1 = malloc(sizeof(struct foo)+30); // takes advantage of sizeof(char)==1

получить место для 30 объектов в массиве значений . Вам все равно нужно будет сделать

foo1->offsets = malloc(30*sizeof(short));

если вы хотите, чтобы они использовали массивы одинакового размера.

На самом деле я бы этого не делал (кошмар сопровождения, если структуре когда-нибудь понадобится расширяться), но это инструмент в наборе.

.

[код здесь в с. Нужно прописать malloc (или лучше использовать new и RAII идиомы) в с++]

3
ответ дан 6 December 2019 в 04:52
поделиться

Для этого нужна функция. Что-то вроде (мой C/C++ заржавел)

swc* makeStruct(int offsetCount, int valuesCount) {
  swc *ans = new swc();
  ans->offset = new short[offsetCount];
  ans->values = new char[valuesCount];
  return ans;
}

myNewStruct = makeStruct(4, 20);

Синтаксис может быть немного неаккуратен, но в целом это то, что вам понадобится. Если Вы используете C++, то вероятно Вам нужен класс с конструктором, принимающим 2 аргумента вместо makeStruct, но делающим что-то очень похожее.

.
3
ответ дан 6 December 2019 в 04:52
поделиться

В C:

typedef struct
{
    short *offset;
    char  *values;
} swc;

/// Pre-Condition:  None
/// Post-Condition: On failure will return NULL.
///                 On Success a valid pointer is returned where
///                 offset[0-n) and values[0-n) are legally de-refrancable.
///                 Ownership of this memory is returned to the caller who
///                 is responsible for destroying it via destroy_swc()
swc *create_swc(unsigned int size)
{
    swc *data    = (swc*)  malloc(sizeof(swc));
    if (data)
    {
        data->offset = (short*)malloc(sizeof(short)*n);
        data->values = (char*) malloc(sizeof(char) *n);
    }
    if ((data != NULL) && (size != 0) && ((data->offset == NULL) || (data->values == NULL)))
    {
        // Partially created object is dangerous and of no use.
        destroy_swc(data);
        data = NULL;
    }
    return data;
}
void destroy_swc(swc* data)
{
    free(data->offset);
    free(data->values);
    free(data);
}

В C++

struct swc
{
    std::vector<short>   offset;
    std::vector<char>    values;
    swc(unsigned int size)
        :offset(size)
        ,values(size)
    {}
};
4
ответ дан 6 December 2019 в 04:52
поделиться

Вы должны сделать это отдельно. Сначала выделить структуру, затем память для массивов.

В C:

swc *pSwc = malloc(sizeof(swc));
pSwc->offset = malloc(sizeof(short)*offsetArrayLength);
pSwc->values = malloc(valuesArrayLength);

В C++ не следует делать ничего подобного.

.
4
ответ дан 6 December 2019 в 04:52
поделиться

В C:

swc *s = malloc(sizeof *s); // assuming you're creating a single instance of swc
if (s)
{
  s->offset = malloc(sizeof *(s->offset) * number_of_offset_elements);
  s->values = malloc(sizeof *(s->values) * number_of_value_elements);
}

В C++:

try
{
  swc *s = new swc;
  s->offset = new short[number_of_offset_elements];
  s->values = new char[number_of_value_elements];
}
catch(...)
{
   ...
}

Обратите внимание, что в C++, возможно, лучше использовать векторы, а не динамически выделяемые буферы:

struct swc 
{
  std::vector<short> offset;
  std::vector<char> values;
};

swc *a = new swc;

Вопрос: предполагается ли, что значения представляют собой массив отдельных символов или массив строк? Это немного изменит ситуацию.

EDIT

Чем больше я думаю об этом, тем меньше я доволен ответом C++; правильный правый способ делать подобные вещи на C++ (предполагая, что Вам нужен динамически выделяемые буферы, а не векторы, чего Вы, вероятно, не делаете) - это выполнить выделение памяти для смещения и значений как части конструктора внутри типа struct и заставить деструктор разобраться с этими элементами при уничтожении экземпляра структуры (либо с помощью delete, либо выходя за пределы видимости).

struct swc
{
  swc(size_t numOffset = SOME_DEFAULT_VALUE, 
      size_t numValues = SOME_OTHER_DEFAULT_VALUE)
  {
    m_offset = new short[numOffset];
    m_values = new char[numValues];
  }

  ~swc()
  {
    delete[] m_offset;
    delete[] m_values;
  }

  short *m_offset;
  char  *m_values;
};

void foo(void)
{
  swc *a = new swc(10,20); // m_offset and m_values allocated as 
                           // part of the constructor
  swc b;                   // uses default sizes for m_offset and m_values
  ...
  a->m_offset[0] = 1;
  a->m_values[0] = 'a';
  b.m_offset[0] = 2;
  b.m_values[0] = 'b';
  ...
  delete a; // handles freeing m_offset and m_values
            // b's members are deallocated when it goes out of scope
}
9
ответ дан 6 December 2019 в 04:52
поделиться
[

][]**Если**[] вы не будете изменять размер массивов, то сможете избежать одиночного вызова функции []malloc()[].[

]. [
swc *new_swc (int m, int n) {
    swc *p;
    p = malloc (sizeof (*p) + m * sizeof (p->offset[0]) + n * sizeof (p->values[0]);
    p->offset = (short *) &p[1];
    p->values = (char *) &p->offset[m];
    return p;
}
] [

] Затем можно освободить его одним вызовом на [] free()[].[

]. [

](В общем, есть соображения по выравниванию, но для массива шортов, за которым следует массив символов, все будет хорошо)[

].
0
ответ дан 6 December 2019 в 04:52
поделиться

Так как об этом еще никто не упоминал, иногда бывает приятно захватить этот кусок памяти за одно распределение, поэтому вам нужно вызывать free() только по одному поводу:

swc* AllocSWC(int items)
{
    int size = sizeof(swc); // for the struct itself
    size += (items * sizeof(short)); // for the array of shorts
    size += (items * sizeof(char)); // for the array of chars
    swc* p = (swc*)malloc(size);
    memset(p, 0, size);
    p->offset = (short*)((char*)swc + sizeof(swc)); // array of shorts begins immediately after the struct
    p->values = (char*)((char*)swc + sizeof(swc) + items * sizeof(short)); // array of chars begins immediately after the array of shorts
    return p;
}

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

1
ответ дан 6 December 2019 в 04:52
поделиться