Участник массива с переменными границами в C-структуре

Заключение в кавычки от C-std разделяет 6.7.2.1,

struct s { int n; double d[]; };

Это - действительное описание структуры. Я ищу некоторое практическое применение этого вида синтаксиса. Быть точным, как больше эта конструкция или менее мощна, чем хранение двойного* как 2-й элемент? Или этот другой случай 'you-can-do-it-in-multiple-ways''?

Arpan

5
задан M.M 3 November 2014 в 20:36
поделиться

4 ответа

FAQ по C отвечает именно на этот вопрос. Быстрый ответ заключается в том, что эта структура будет включать массив double внутри структуры, а не указатель на массив вне структуры. В качестве краткого примера, вы можете использовать вашу структуру как в этом примере:

struct s mystruct = malloc(sizeof(struct s) + 5 * sizeof(double));
s.n = 12;
s.d[0] = 4.0;
s.d[1] = 5.0;
s.d[2] = 6.0;
s.d[3] = 7.0;
s.d[4] = 8.0;

И так далее - размер массива, о котором вы заботитесь, включается в выделение, и затем вы можете использовать его как любой массив. Обычно такой тип содержит размер как часть структуры, поскольку использование трюка + для пропуска через массив типа s будет обязательно осложнено этой ситуацией.

На ваш дополнительный вопрос "чем эта конструкция более или менее мощная, чем хранение [указателя] в качестве второго элемента?", она не более мощная сама по себе, но вам не нужно держать указатель рядом, так что вы сэкономите по крайней мере столько места - также при копировании структуры вы копируете массив, а не указатель на массив - тонкая разница иногда, но очень важная в другое время. 'You-can-do-it-in-multiple-ways' - это, вероятно, хорошее объяснение, но есть случаи, когда вам конкретно нужна та или иная конструкция.

10
ответ дан 18 December 2019 в 10:42
поделиться

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

typedef struct {
    SIZE_T bytes;
    TCHAR chars[];
} tagged_string;
0
ответ дан 18 December 2019 в 10:42
поделиться

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

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

4
ответ дан 18 December 2019 в 10:42
поделиться

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

struct int_array
{
    size_t size;
    int values[];
};

struct int_array *foo = malloc(sizeof *foo + 42 * sizeof *foo->values);
foo->size = 42;

...

for(size_t i = 0; i < foo->size; ++i)
    foo->values[i] = i * i;

Вы можете добиться аналогичных результатов, используя вместо этого член int * и выделяя массив отдельно, но он был бы менее эффективным как с точки зрения памяти (дополнительный указатель, управление кучей для 2-го блока памяти), так и времени выполнения (дополнительное косвенное обращение, 2-е выделение).

2
ответ дан 18 December 2019 в 10:42
поделиться
Другие вопросы по тегам:

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