Я пытаюсь прочитать текстовый файл в связанный список, который содержит как целые числа, так и строки в строке, разделенные запятыми

Я создаю базу данных, где информация о книгах и читателях в библиотеке содержится в двух связанных списках, а каждая строка txt файла содержит данные одной книги/людей в библиотеке. Данные книг: id;год;название;писатель;заимствовано;\n ...

Идентификатор и isborrowed(1or0) — целые числа, остальные — строки. Я знаю, что atoi может преобразовывать входные строки в числа, но когда я использую его, разделяя каждую строку запятыми, это просто не работает, печать неверна, а также я не могу вернуться с указателем *start/*begin , где начинается список. К настоящему времени я совершенно невежественен, потому что это не первый метод, который я пробовал.

Часть кода:

#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <stdlib.h>

typedef struct Konyv{
int id;
char *year;
char *title;
char *writer;
int ki;
struct Konyv*next;
}Konyv;


int main(){

Konyv*start=NULL;

FILE*f;


const char s[1] = ";";
int i;
f=fopen("konyv.adat.txt","r+");
Konyv*u;

if(f != NULL){
    char line[1000];
    while(fgets(line, sizeof line, f) !=NULL){
        u= (Konyv*)malloc(sizeof(Konyv));
        u->id = strtok(line, s);
        u->id=atoi(u->id);
        printf("%d ",u->id);
        u->year = strtok(NULL,s);
        printf("%s ",u->year);
        u->title = strtok(NULL,s);
        printf("%s ",u->title);
        u->writer = strtok(NULL,s);
        printf("%s ",u->writer);
        u->ki = strtok(NULL,s);
        u->ki=atoi(u->ki);
        printf("%d",u->ki);
        printf("\n");
        u->next=NULL;

        if(start==NULL){
                start=u;
            }
        else{
            Konyv *mozgo = start;
            while (mozgo->next!= NULL){
                mozgo = mozgo->next;
            }
            mozgo->next= u;
        }

    }


else{
    printf("Error while opening.\n");
    return 0;
}

printf("\n");
//test if start pointer is right by printig the list again(HELP)

Konyv* temp;
temp=start;
while(temp!=NULL) {
printf("%d ",temp->id);
printf("%s ",temp->year);
printf("%s ",temp->title);
printf("%s ",temp->writer);
printf("%d ",temp->ki);
printf("\n");
temp = temp->next;
}

free(u);
fclose(f);

return 0;
}

person David69420    schedule 29.11.2020    source источник
comment
Я надеюсь, вы понимаете, что strtok возвращает адреса в исходном буфере, с которого он был запущен, т.е. вы продолжаете повторно использовать этот буфер (в вашем случае line), сохраняя strtok указателей результатов в некоторых узлах связанного списка, и каждый узел в списке будет иметь указатели, ссылающиеся на места с той же буферной памятью, но только последние один будет иметь смысл. Это объясняет туманное неправильное условие печати, о котором вы упомянули.   -  person WhozCraig    schedule 29.11.2020


Ответы (1)


@WhozCraig верен и заимствован из в этом посте вы можете видеть, что нам просто нужно скопировать данные по указателю на новый кусок памяти. Для этого мы можем использовать функцию strdup, включенную в string.h.

Например:

u->year = strtok(NULL,s);

становится

u->year = strdup(strtok(NULL,s));

Вы можете найти документацию по strdup здесь для дальнейшего использования.

Кроме того, я не хочу оставлять вас здесь, код, который вы передали, не скомпилировался чисто — мне пришлось заполнить некоторые скобки.

Еще одна вещь, которая хранит что-либо, кроме int в вашем поле id, проблематична. Так,

u->id = strtok(line, s);

является проблемой. Простое исправление,

u->id = atoi(strdup(strtok(line, s)));

но это немного грязно и трудно читать для другого программиста, пришедшего поддерживать код. Я бы посоветовал потратить время на объявление переменной только для временного хранения токена, который вы в конечном итоге собираетесь продублировать в своей структуре.

person Astormooke    schedule 29.11.2020