#c #struct
#c #структура
Вопрос:
Я пытаюсь сохранить несколько списков структур следующей спецификации,
typedef struct Example
{
int num1;
int num2;
char* str;
} Example;
Я создаю эти списки из пользовательского / файлового ввода, поэтому размер каждого списка должен быть динамическим.
Мне также нужно было бы сохранить длину каждого списка, поэтому я думаю, что мне понадобится другая структура для хранения списка примеров и его размера.
typedef struct ListOfExamples
{
int length;
Example** examples;
} ListOfExamples;
Если бы я хотел сохранить список ListOfExample, тип был бы следующим, если я не ошибаюсь,
ListOfExample** listOfExampleLists;
Есть ли более чистый / простой способ, которым я мог бы хранить списки списков примеров? Кажется, что для этой задачи выделяется много памяти, и я новичок в C, поэтому я хотел знать, лучший ли это способ сделать это.
Комментарии:
1. «… если я не ошибаюсь» — вы ошибаетесь. Простая динамическая последовательность некоторого типа структуры может быть выполнена с помощью одного косвенного обращения. Т.е.
ListOfExample *listOfExampleLists = malloc(N * sizeof *listOfExampleLists);
, например. Также вероятно, что вы без необходимости используете слишком много уровней косвенности в своемListOfExamples
.
Ответ №1:
Вот пример того, как вы могли бы адаптировать свой код, я думаю, что имена указателей, которые я ввел, объясняют почти все:
Хитрость здесь в том, что каждый элемент второго списка является указателем на первый элемент. И поскольку это список, он должен содержать ссылку на следующий элемент его типа. (Возможно, вы захотите оставить это поле длины вне списка — обычной переменной — если его целью является только подсчет количества элементов, находящихся в данный момент в списке)
typedef struct Example
{
int num1;
int num2;
char* str;
struct Example *next;
} Example;
typedef struct ListOfExamples
{
int length;
Example* examples;
struct ListOfExamples *nextList;
} ListOfExamples;
int main() {
Example *second, *ex; //ex will be the first element of the first list
ex = (Example*)malloc(sizeof(Example));
second = (Example*)malloc(sizeof(Example));
ex->num1 = ex->num2 = 10;
second->num1 = second->num2 = 5;
ex->next = second;
second->next = NULL;
ListOfExamples *listoflist = (ListOfExamples*) malloc(sizeof(ListOfExamples));
listoflist->examples = ex;
listoflist->nextList = NULL;
printf("%dn", listoflist->examples->num1);
printf("%dn", listoflist->examples->next->num1);
}
Ответ №2:
Если вам нужно выделить строку каждой структуры отдельно, будет сложно освободить все вещи. Вместо этого вы могли бы использовать строку фиксированного размера и убедиться, что вы никогда не используете строку длиннее этого предела (здесь 31, поскольку последний символ является нулевым завершением), таким образом, строка выделяется со структурой :
typedef struct Example
{
int num1;
int num2;
char str[32];
} Example;
В списке структур вы должны использовать простой указатель, а не двойной указатель. Лучше, вы можете использовать гибкий массив :
typedef struct ListOfExamples
{
int length;
Example examples[];
} ListOfExamples;
Таким образом, размер вашего ListOfExamples будет составлять всего 4 байта. Если у вас есть 100 списков списков, каждый из которых имеет длину 100, весь материал будет использовать 400 килобайт (4 * 100 * 100 ) 400 байт для списка списков.
Затем вы можете использовать его следующим образом :
int main() {
// For the list of lists you could create a list pointers on the stack with all pointers set to NULL:
ListOfExamples * listOfList[100] = {0};
// Sets the first index of listOfList with an allocated list of size 100 :
listOfList[0] = (ListOfExamples *)malloc(sizeof(ListOfExamples) 100 * sizeof(Example));
listOfList[0]->length = 100;
// The memory for each example is already allocated, you just need to use it :
Example * ex = amp;listOfList[0]->examples[0];
ex->num1 = 27;
ex->num2 = 10;
// The string must be set using memcpy
memcpy(ex->str, "My Birthday", sizeof("My Birthday"));
// Read a structure
Example first = listOfList[0]->examples[0];
printf("%d %d %s", first.num1, first.num2, first.str);
// Finally free the used lists
for (int i=0; i<100; i ) {
if (listOfList[i]) free(listOfList[i]);
}
return 0;
}