Переменная как размер массива в структуре - PullRequest
9 голосов
/ 05 ноября 2010

Я реализую структуру файла в моей программе, но для некоторых массивов в структуре я не знаю размер.Размер массива сохраняется в другой переменной, но он неизвестен до заполнения структуры.

struct Vertex {
    float x;
    float y;
    float z;
};
struct myFile {
    ulong nVertices;
    Vertex vertices[nVertices];
};

Это выдает ошибку: «error C2065: 'nVertices': необъявленный идентификатор».

Ответы [ 2 ]

14 голосов
/ 05 ноября 2010

Вы должны хранить указатель в вашей структуре:

Vertex *vertices;

Затем выделите память во время выполнения:

myFile f;
f.vertices = malloc(nVertices * sizeof(Vertex));
if (f.vertices == 0)
    handle_out_of_memory();

f.nVertices = nVertices;

Не забудьте освободить память, когда закончите:

free(f.vertices);
10 голосов
/ 05 ноября 2010

C99 вводит «гибкие элементы массива», которые могут быть тем, что вы хотите использовать. Ваш код все равно выглядит замечательно, как код, предложенный @ frast , но немного отличается.

§6.7.2.1 Структура и объединение спецификаторов

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

[...]

В особом случае последний элемент структуры с более чем одним именованным элементом может иметь неполный тип массива; это называется членом гибкого массива. С двумя исключения, гибкий член массива игнорируется. Во-первых, размер структуры должен быть равно смещению последнего элемента в остальном идентичной структуры, которая заменяет элемент гибкого массива с массивом неопределенной длины. 106) Второй, когда a. (или ->) Оператор имеет левый операнд, который является (указатель) на структуру с членом гибкого массива и правильный операнд называет этот член, он ведет себя так, как если бы этот член был заменен с самым длинным массивом (с тем же типом элемента), который не сделал бы структуру больше, чем объект, к которому осуществляется доступ; смещение массива должно оставаться смещение гибкий элемент массива, даже если это будет отличаться от элемента массива замены. Если это массив не имеет элементов, он ведет себя так, как если бы он имел один элемент, но поведение не определено, если предпринята какая-либо попытка получить доступ к этому элементу или сгенерировать указатель за один раз это.

ПРИМЕР Предполагая, что все члены массива выровнены одинаково после объявлений:

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

Три выражения:

sizeof (struct s)
offsetof(struct s, d)
offsetof(struct ss, d)

имеют одинаковое значение. Структура struct s имеет гибкий член массива d.

Если sizeof (double) равен 8, то после выполнения следующего кода:

struct s *s1;
struct s *s2;
s1 = malloc(sizeof (struct s) + 64);
s2 = malloc(sizeof (struct s) + 46);

и при условии, что вызовы malloc успешны, объекты, на которые указывают s1 и s2, ведут себя так, как если бы идентификаторы были объявлены как:

struct { int n; double d[8]; } *s1;
struct { int n; double d[5]; } *s2;

После дальнейших успешных заданий:

s1 = malloc(sizeof (struct s) + 10);
s2 = malloc(sizeof (struct s) + 6);

тогда они ведут себя так, как если бы объявления были:

struct { int n; double d[1]; } *s1, *s2;

и

double *dp;
dp = &(s1->d[0]); // valid
*dp = 42; // valid
dp = &(s2->d[0]); // valid
*dp = 42; // undefined behavior

Назначение:

*s1 = *s2;

копирует только элемент n, но не элементы массива. Точно так же:

struct s t1 = { 0 }; // valid
struct s t2 = { 2 }; // valid
struct ss tt = { 1, { 4.2 }}; // valid
struct s t3 = { 1, { 4.2 }}; // invalid: there is nothing for the 4.2 to initialize
t1.n = 4; // valid
t1.d[0] = 4.2; // undefined behavior

106) Длина не указана, чтобы учесть тот факт, что реализации могут давать разные элементы массива выравнивания в соответствии с их длиной.

Пример взят из стандарта C99.

...