Как распределить память динамически для struct [duplicate]

36
задан Ciro Santilli 新疆改造中心 六四事件 法轮功 4 May 2016 в 15:46
поделиться

8 ответов

То, как вы его написали сейчас, раньше называлось «struct hack», пока C99 не благословил его как «гибкий элемент массива». Причина, по которой вы получаете ошибку (возможно, в любом случае), состоит в том, что за ней должна следовать точка с запятой:

#include <stdlib.h>

struct my_struct {
    int n;
    char s[];
};

Когда вы выделяете место для этого, вы хотите выделить размер структуры plus объем пространства, который вы хотите для массива:

struct my_struct *s = malloc(sizeof(struct my_struct) + 50);

В этом случае гибкий элемент массива представляет собой массив символов char и sizeof (char) == 1, поэтому вам не нужно умножать его размер, но так же, как и любой другой malloc, который вам нужен, если бы он был массивом какого-либо другого типа:

struct dyn_array { 
    int size;
    int data[];
};

struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int));

Edit: Это дает другой результат от изменения элемента до указателя. В этом случае вам (обычно) нужны два отдельных распределения: один для самой структуры и один для «дополнительных» данных, на которые указывает указатель. Используя гибкий член массива, вы можете выделить все данные в одном блоке.

61
ответ дан Basile Starynkevitch 25 August 2018 в 10:36
поделиться

Арифметика указателя быстрее, чем массивы, да?

Совсем нет - они на самом деле одинаковы. массивы переводят на арифметику указателя во время компиляции.

char test[100];
test[40] = 12;

// translates to: (test now indicates the starting address of the array)
*(test+40) = 12;
0
ответ дан Alexander Gessler 25 August 2018 в 10:36
поделиться

Вам нужно решить, что именно вы пытаетесь сделать первым.


Если вы хотите иметь структуру с указателем на [независимый] массив внутри, вы должны объявить это как

struct my_struct { 
  int n; 
  char *s;
}; 

В этом случае вы можете создать фактический объект структуры любым способом (например, как автоматическая переменная)

struct my_struct ms;

, а затем выделить память для массива независимо

ms.s = malloc(50 * sizeof *ms.s);  

На самом деле нет общей необходимости динамически распределять память массива

struct my_struct ms;
char s[50];

ms.s = s;

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

Обратите внимание, что в этом случае у вас есть два независимых блока памяти: структура и массив.


Совершенно другой подход заключается в использовании идиомы «struct hack». В этом случае массив становится неотъемлемой частью структуры. Оба находятся в одном блоке памяти. В C99 структура будет объявлена ​​как

struct my_struct { 
  int n; 
  char s[];
}; 

и для создания объекта, который вам нужно будет динамически выделять все это

struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);

Размер блока памяти в этом case рассчитан для размещения элементов структуры и конечного массива времени выполнения.

Обратите внимание, что в этом случае у вас нет возможности создавать такие объекты структуры, как статические или автоматические объекты. Структуры с гибкими членами массива в конце могут быть динамически распределены только на C.


Ваше предположение о том, что арифметика указателя быстрее, чем массивы, абсолютно неверна. Массивы работают по указателю арифметики по определению, поэтому они в основном одинаковы. Более того, подлинный массив (не распадающийся на указатель), как правило, немного быстрее, чем объект-указатель. Значение указателя должно считываться из памяти, а местоположение массива в памяти «известно» (или «вычислено») из самого массива.

17
ответ дан AnT 25 August 2018 в 10:36
поделиться

Я подозреваю, что компилятор не знает, сколько места ему нужно будет выделять для s [], если вы решите объявить с ним автоматическую переменную.

Я согласен с тем, что сказал Бен, объявить ваша структура

struct my_struct {
    int n;
    char s[1];
};

Кроме того, чтобы прояснить его комментарий о хранении, объявление char *s не будет помещать структуру в стек (поскольку оно динамически распределено) и выделять s в кучу, что он будет делать, это интерпретировать первые sizeof(char *) байты вашего массива в качестве указателя, так что вы не будете работать с данными, которые, по вашему мнению, являетесь вами, и, вероятно, будут фатальными.

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

0
ответ дан Duncan 25 August 2018 в 10:36
поделиться

Существует множество ответов относительно гибкого массива C99.

Я хотел бы прокомментировать ответ Александра Гесслера относительно указателей, являющихся такими же, как массивы.

Они не являются; Массивы - это выражение, указатели - переменная.

У них есть тонкие отличия, особенно при пересечении больших объемов данных. Иногда вам нужно выжимать каждый mSec (я работаю над встроенными графическими системами).

0
ответ дан Fred 25 August 2018 в 10:36
поделиться

Использование массива неопределенного размера допускается только в конце структуры и работает только в некоторых компиляторах. Это нестандартное расширение компилятора. (Хотя я думаю, что я помню, что C ++ 0x разрешит это.)

Однако массив не будет отдельным распределением из структуры. Поэтому вам нужно выделить все my_struct, а не только часть массива.

Что я делаю, просто дайте массиву небольшой, но ненулевой размер. Обычно 4 для массивов символов и 2 для wchar_t массивов для сохранения 32-битного выравнивания.

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

Кроме того, я думаю, вы не должны использовать sizeof (char *) в своем распределении.

Это то, что я сделал бы.

struct my_struct {
    int nAllocated;
    char s[4]; // waste 32 bits to guarantee alignment and room for a null-terminator
};

int main()
{
    struct my_struct * pms;
    int cb = sizeof(*pms) + sizeof(pms->s[0])*50;
    pms = (struct my_struct*) malloc(cb);
    pms->nAllocated = (cb - sizoef(*pms) + sizeof(pms->s)) / sizeof(pms->s[0]);
}
1
ответ дан John Knoeller 25 August 2018 в 10:36
поделиться

Массивы будут разрешены указателями, и здесь вы должны определить s как char *s. Структура в основном представляет собой контейнер и должна (IIRC) быть фиксированным размером, поэтому наличие внутри нее массива динамического размера просто невозможно. Так как вы все равно malloc в памяти, это не должно иметь никакого значения в том, что вам нужно.

В основном вы говорите, s укажет место памяти. Обратите внимание, что вы можете получить доступ к этому позже, используя нотацию, такую ​​как s[0].

0
ответ дан Mark Elliot 25 August 2018 в 10:36
поделиться

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

и BTW - сделайте это c ++ и используйте вектор

-6
ответ дан pm100 25 August 2018 в 10:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: