简体   繁体   中英

Reading linked list from txt file in C

I'm trying to read my linked list from file with no luck. Struct is properly saved with fprintf (couldn't get it to work with fwrite). Here is my struct:

typedef struct database
{
    int id;
    int nrindeksu;
    char *imie;
    char *nazwisko;
    char *wydzial;
    char *kierunek;
    struct database* link;
} data;

char buffer[1024]; //changed buffer size

I'm saving linked list to file using this function: Edit: After some changes to other functions this one crashes.

void save(data* head)
{
    FILE *fp;
    fp = fopen("test.txt", "w");
    data* current = head->link;

    while (current != NULL) {
        fprintf(fp,"%d ",current->nrindeksu);
        fprintf(fp,"%s ",current->imie);
        fprintf(fp,"%s ",current->nazwisko);
        fprintf(fp,"%s ",current->wydzial);
        fprintf(fp,"%s\n",current->kierunek);
        current = current->link;
    }
    fclose(fp);
}

and trying to read it from file with this:

void read(data* head)
{
    data* current = head;
    FILE *fp;
    fp = fopen("test.txt", "r");

    while(//I still need help with this loop)
    fscanf(fp, "%d", current->link->nrindeksu);

    fscanf(fp, "%s", buffer);
    current->link->imie=malloc(strlen(buffer) + 1);
    if(current->link->imie == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->imie, buffer);

    fscanf(fp, "%s", buffer);
    current->link->nazwisko=malloc(strlen(buffer) + 1);
    if(current->link->nazwisko == NULL) {
        fprintf(stderr, "Malloc error");
        exit(0);
    }
    strcpy(current->link->nazwisko, buffer);

    fscanf(fp, "%s", buffer);
    current->link->wydzial=malloc(strlen(buffer) + 1);
    if(current->link->wydzial == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->wydzial, buffer);

    fscanf(fp, "%s", buffer);
    current->link->kierunek=malloc(strlen(buffer) + 1);
    if(current->link->kierunek == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->kierunek, buffer);

    fclose(fp);
}

Any idea why it doesn't read anything? Also I don't know how to code a loop that will determine where it should stop reading from file.

Edit: I'm using this function to add items to the list:

void add_bottom(data* head) 
{
    data* current = head;

    while (current->link != NULL)
    {       
        current = current->link;
    }

    current->link = malloc(sizeof(*current));//changed every malloc 
    if(current->link == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }

    printf("Podaj nr indeksu studenta: ");
    scanf("%d", current->link->nrindeksu);

    printf("Podaj imie studenta: ");
    fflush(stdin);
    scanf("%19[^\n]", buffer);
    current->link->imie=malloc(strlen(buffer) + 1);
    if(current->link->imie == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->imie, buffer);

    printf("Podaj nazwisko studenta: ");
    fflush(stdin);
    scanf("%19[^\n]", buffer);
    current->link->nazwisko=malloc(strlen(buffer) + 1);
    if(current->link->nazwisko == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->nazwisko, buffer);

    printf("Podaj wydzial studenta: ");
    fflush(stdin);
    scanf("%29[^\n]", buffer);
    current->link->wydzial=malloc(strlen(buffer) + 1);
    if(current->link->wydzial == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->wydzial, buffer);

    printf("Podaj kierunek studenta: ");
    fflush(stdin);
    scanf("%29[^\n]", buffer);
    current->link->kierunek=malloc(strlen(buffer) + 1);
    if(current->link->kierunek == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->kierunek, buffer);

    current->link->link = NULL;
}

Main:

int main(int argc, char *argv[]) 
{
    char c;
    head = init(head);
    if(head == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    read(head);
    do{
        printf("Baza danych - wybierz opcje: [d]odaj, [w]yswietl, [u]sun, [k]oniec: ");
        scanf("%c", &c);
        if(c=='d')
        {
            system("cls");
            add_bottom(head);
        }
        if(c=='w')
        {
            system("cls");
            show(head);
        }
        if(c=='u')
        {
            system("cls");
            show(head);
            remove_by_id(&head);
            system("cls");
            show(head);
            printf("\n");
        }
        fflush(stdin);

    }while(c!='k');
    save(head);
    free(head);
    return 0;
}

Also function init is just

head = calloc(1,sizeof(data));

This way first node is always NULL, couldn't get it to work other way to create or edit first node.

The comments site several issues with your code. For illustration on a few of them...

The statements (6 of them):

fscanf("%d", &nrindeksu);

...as is will not allow the code you posted to compile, as fscanf() requires FILE * to be used as the first argument.

fscanf(fp, "%d", &nrindeksu);

The function strlen(nazwisko) (as with all other similar lines in your post) returns only the length of the buffer without accounting for the NULL terminator, which will be required of the length of the receiving buffer, current->link->nazwisko .

At the very least, you can address this by adding space for the NULL terminator explicitly:

current->link->nazwisko=(char*)malloc(sizeof(char) * strlen(nazwisko) + 1);
                        ^^^^^^^       ^^^^^^^^^^^^^^                  ^^^
                            not necessary                          necessary

Because sizeof(char) is always == 1, it is not necessary

Cleaned up:

current->link->nazwisko=malloc(strlen(nazwisko) + 1);

Or, as suggested in the comments (if POSIX is an option) you can use strdup()

char *tmp = 0;
tmp = strdup(nazwisko);
if(tmp)
{
     current->link->nazwisko = tmp;
     strcpy(current->link->nazwisko, nazwisko);
}

Another minor point. The following is legal, and does allocate sufficient space:

current->link = malloc(sizeof(data));

But this form:

current->link = malloc(sizeof(*current));

is generally recommended as it is better that the variable , not the type be used in the sizeof expression.

One additional comment, it is not necessary to cast the return of [m][c]alloc when using C .

EDIT (edits to your code that allow it to compile and run. [ complete with memory leaks ])

//does not include global declarations of struct data and variables
void read(data** head); //so object can be changed when passes as function argument
//             ^
void save(data* head);


int main(void)
{
    data *h = calloc(1, sizeof(data));
    read(&h);  //note, passing to data **, not data *
    save(h);

    return 0;
}

void save(data* head)
{
    FILE *fp;
    fp = fopen("text2.txt", "w");
    //data* current = head->link;

    fprintf(fp,"%d ",head->link->nrindeksu);
    fprintf(fp,"%s ",head->link->imie);
    fprintf(fp,"%s ",head->link->nazwisko);
    fprintf(fp,"%s ",head->link->wydzial);
    fprintf(fp,"%s\n",head->link->kierunek);
    fclose(fp);
}


void read(data **head)
{
    data *current = calloc(1, sizeof(*current));
    current = *head;
    int count;
    FILE *fp;
    fp = fopen(".\\text.txt", "r");

    {
        current->link = malloc(sizeof(data));
        if(current->link == NULL) {
            fprintf(stderr, "Malloc error"); 
            exit(0);
        }
        count = fscanf(fp,"%d %s %s %s %s", &nrindeksu, imie, nazwisko, wydzial, kierunek);
        if(count != 5)
        {
            free(current);
            return 
        }
        current->link->nrindeksu = nrindeksu;

        current->link->imie=(char*)malloc(sizeof(char) * strlen(imie)+1);
        if(current->link->imie == NULL) {
            fprintf(stderr, "Malloc error"); 
            exit(0);
        }
        strcpy(current->link->imie, imie);

        current->link->nazwisko=(char*)malloc(sizeof(char) * strlen(nazwisko)+1);
        if(current->link->nazwisko == NULL) {
            fprintf(stderr, "Malloc error"); 
            exit(0);
        }
        strcpy(current->link->nazwisko, nazwisko);

        current->link->wydzial=(char*)malloc(sizeof(char) * strlen(wydzial)+1);
        if(current->link->wydzial == NULL) {
            fprintf(stderr, "Malloc error"); 
            exit(0);
        }
        strcpy(current->link->wydzial, wydzial);

        current->link->kierunek=(char*)malloc(sizeof(char) * strlen(kierunek)+1);
        if(current->link->kierunek == NULL) {
            fprintf(stderr, "Malloc error");         
            exit(0);
        }
        strcpy(current->link->kierunek, kierunek);

        current->link->link = NULL; 
    }
    fclose(fp);
}

Note: the above code does read the data into a node, and is able write the node data into a file, but you will have to do the memory clean up. Nothing is freed. The link I posted in comments above will help to address that.

EDIT 2 (based on functions in this tutorial link )

The following will read text file (see example file at bottom of code) into a linked list, then write the contents of the list into a second text file, then clean up all the memory used.

typedef struct database
{
    int id;
    int nrindeksu;
    char *imie;
    char *nazwisko;
    char *wydzial;
    char *kierunek;
    struct database* link;
}data;

typedef struct {
    int id;
    int nrindeksu;
    char imie[20];
    char nazwisko[20];
    char wydzial[30];
    char kierunek[30];
}LINE;

LINE line;

void push(data** head_ref, LINE *line);
void store(data *d, FILE *p);
void cleanup(data *d);

int main(void)
{
    data *head = NULL;
    FILE *fp;
    fp = fopen(".\\text1.txt", "r");
    if(fp)
    {
        while(fscanf(fp,"%d %s %s %s %s", &line.nrindeksu, line.imie, line.nazwisko, line.wydzial, line.kierunek)== 5)
        {
            push(&head, &line); 
        }
        fclose(fp);
    }
    fp = fopen(".\\text2.txt", "w");
    if(fp)
    {
        store(head, fp);
        fclose(fp);
    }
    cleanup(head);
    return 0;
}

/// synonymous with your "read()" 
void push(data** head_ref, LINE *line)
{
    /* 1. allocate node */
    data *new_node = malloc(sizeof(*new_node));

    /* 2. put in the data  */
    new_node->id  = line->id;
    new_node->nrindeksu  = line->nrindeksu;
    new_node->imie = calloc(1, strlen(line->imie)+1);
    strcpy(new_node->imie, line->imie); 
    new_node->nazwisko = calloc(1, strlen(line->nazwisko)+1);
    strcpy(new_node->nazwisko, line->nazwisko); 
    new_node->wydzial = calloc(1, strlen(line->wydzial)+1);
    strcpy(new_node->wydzial, line->wydzial); 
    new_node->kierunek = calloc(1, strlen(line->kierunek)+1);
    strcpy(new_node->kierunek, line->kierunek); 

    /* 3. Make next of new node as head */
    new_node->link = (*head_ref);

    /* 4. move the head to point to the new node */
    (*head_ref)    = new_node;
}


void store(data *d, FILE *p)
{
    char line[260];
    while(d != NULL)
    {
        sprintf(line, "%d %s %s %s %s\n", d->nrindeksu, d->imie, d->nazwisko, d->wydzial, d->kierunek);
        fputs(line, p);
        d = d->link;
    }
}

void cleanup(data *d)
{
    data *tmp;

    while(d != NULL)
    {
        tmp = d;

        if(tmp->imie)   free(d->imie);
        if(tmp->nazwisko) free(d->nazwisko);
        if(tmp->wydzial)    free(d->wydzial);
        if(tmp->kierunek) free(d->kierunek);
        d = d->link;
        free(tmp);
    }
    free(d);
}

Text file referenced as input for code sample:

text1.txt:

0 string01 string02 string03 string04
1 string11 string12 string13 string14
2 string21 string22 string23 string24
3 string31 string32 string33 strin3g4
4 string41 string42 string43 string44
5 string51 string52 string53 string54
6 string61 string62 string63 string64
7 string71 string72 string73 string74
8 string81 string82 string83 string84
9 string91 string92 string93 string94

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM