C хранение списка списков структур

#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;
}