Переменной, как размер массива в структуру
я реализую структуру файла в своей программе, но для некоторых массивов в структуре я не знаю размер. Размер массива хранится в другой переменной, но он неизвестен до заполнения структуры.
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.