Переменной, как размер массива в структуру

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

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

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

2 ответов


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

Vertex *vertices;

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

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

f.nVertices = nVertices;

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

free(f.vertices);

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

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

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

[...]

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

пример, предполагающий, что все члены массива выравниваются одинаково, после объявления:

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

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

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

имеют одинаковое значение. Структура structure 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, ведут себя так, как если бы идентификаторы были объявлены as:

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.