fread и fwrite связанный список в C

#c #linked-list #fwrite #fread

#c #связанный список #fwrite #fread

Вопрос:

Вот моя структура:

 struct Car{
    char plateNum[10];
    char returnDate[7];
    int milage;
    float income;
    struct Car * next;
};
typedef struct Car Car;
 

Мне нужно использовать fwrite и fread для сохранения значения и последующей загрузки. Есть ли простой способ?

Комментарии:

1. Прочитайте о сериализации

2. Нет простого способа, пока вы не напишете функцию, которая это делает. Тогда есть.

3. Просто помните, что значение ссылки struct Car * next; , записанной в file, устареет при перезагрузке данных из file. Вы будете использовать входные данные для создания нового списка, элемент за элементом, ссылка за ссылкой.

4. Как сказал @WeatherVane, крайне важно, чтобы вы не пытались повторно использовать какие-либо значения указателей, которые вы записываете в файл.

Ответ №1:

Для записи LL в файл

 // Be sure to have opened the file in binary mode

Car *x = head;

// Walk the list and write each node.
// No need to write the next field - which happens to be the last one.
//                    v-----------------v size of data before the `next` field
while (x amp;amp; fwrite(x, offsetof(Car, next), 1, out_stream) == 1) {
  x = x->next;
}
 

Для чтения записей из файла в LL и возврата головного узла:

 #include <stddef.h>

// Be sure to have opened the file in binary mode
Car *ReadCars(FILE *in_stream) {
  Car Top;
  Top.next = NULL; // code only uses the `next` field of Top

  Car *previous = amp;Top;
  Car x;

  // While another record was successfully read ...
  while (fread(amp;x, offsetof(Car, next), 1, in_stream) == 1) {
    // Fill the next field
    x.next = NULL;

    // Allocate space and copy
    previous->next = malloc(sizeof *(previous->next));
    assert(previous->next);
    *(previous->next) = x;

    // Advance to the next
    previous = previous->next;
  }
  return Top.next;
}
 

Комментарии:

1. Если я хочу получать по одному автомобилю за раз при чтении и сохранении во временных переменных, а затем вызывать функцию addToBack для создания списка, могу ли я настроить ваш код для этого?

2. @RyanClaxton Я не знаком addToBack() и не могу хорошо ответить на ваш комментарий, но, вероятно, этот код может быть изменен в соответствии с вашими потребностями. Но если addToBack() это то, о чем я думаю, то это был бы плохой способ сделать это, если addToBack() бы приходилось многократно спускаться по лестнице, чтобы найти ее конец.

3. У меня есть фиктивный узел, который хранит конец списка .. моему компилятору не нравится «утверждать» — подождите, я думаю, что смогу это сделать..

4. @RyanClaxton Использовать #include <assert.h>

5. Обратите внимание, что код может сначала выделить пространство, а затем fread() непосредственно в это пространство. Этот подход показался более наглядным.

Ответ №2:

Следующее было написано мной без обиняков и не было протестировано, поэтому может потребоваться доработка. Пожалуйста, также обратите внимание; ради экономии времени я не проверял возвращаемое значение fwrite и fread или не проверял ошибки чтения. ВЫ ДОЛЖНЫ ЭТО СДЕЛАТЬ.

Запись файла

 int length = lengthOfList(bar); // Assuming you've already created bar as a linked list of Cars
Car foo[length];
putLinkedListIntoArray(amp;bar, foo); 

FILE* fh = NULL;

if((fh = fopen("filename", "wb")) == NULL) {
    // Error and die
}

fwrite(amp;length, sizeof(int), 1, fh);
fwrite(bar, sizeof(Car), length, fh);
fclose(fh);
 

Чтение файла

 FILE* fh = NULL;

if((fh = fopen("filename", "rb")) == NULL) {
    // Error and die
}

int length;

fread(amp;length, sizeof(int), 1, fh);

Car foo[length];
fread(foo, sizeof(Car), length, fh);
fclose(fh);
relinkCarList(foo, length);
 

Функции

 int lengthOfList(Car* start) {
   int length;
   for(length = 0; start->next != NULL; length  ) {
       start = start->next;
   }
   return length;
}

void putLinkedListIntoArray(Car* start, Car* array) {
   for(int i = 0; start->next != NULL; i  ) {
       array[i] = *start;
       start = start->next;
   }
}

void relinkCarList(Car* array, int length) {
   for(int i = 0; i < length; i  ) {
       if(i < length - 1) {
           array[i].next = array[i   1].next;
       }
   }
}
 

Комментарии:

1. fwrite(bar, ...) должно быть fwrite(foo, ...) в первом блоке кода. Вы также используете массивы переменной длины (новые в C99). Также кажется неэффективным преобразовывать в массив только для того, чтобы иметь возможность выполнить один вызов fwrite.

2. Я согласен с @dwks. Я думаю, было бы более практично выполнять последовательные fwrite s, пока вы не дойдете до конца связанного списка. В конце концов, OP хочет сделать это со связанными списками, а не с массивом.