#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 хочет сделать это со связанными списками, а не с массивом.