2

Im making a database, where the information about books and readers in a library are contained in two linked lists, and each line of the txt file contains the data of one book/peopleinlibrary. Data of the books: id;year;title;writer;isborrowed;\n ...

The id and the isborrowed(1or0) are integers, the rest are strings. I know the atoi can convert the input lines to numbers, but when I use it while separating each line by commas, it just doesn't work, the printig is wrong and also i can't return with the *start/*begin pointer, where the list starts. By now im totally clueless because it's not the first method that I tried.

The part of the code:

#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;
}
David69420
  • 21
  • 1
  • I hope you realize `strtok` returns addresses within the origin buffer it was kicked off with I.e. you keep reusing that buffer (in your case `line`), storing `strtok` result pointers into some linked list nodes, and every node in the list will have pointers referring to locations with the same buffer memory, but only the *last* one will make any sense. That explains the otherwise-nebulous "printing wrong" condition you mentioned. – WhozCraig Nov 29 '20 at 16:33

1 Answers1

0

@WhozCraig is correct, and borrowing from this post you can see that we simply need to copy the data at the pointer to a new chunk of memory. For this we can use the strdup function included in string.h.

For example:

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

becomes

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

You can find documentation on strdup here for further reference.

Also, I don't want to leave you hanging here, the code you handed over didn't compile cleanly -- I had to complete some brackets.

One final thing storing anything other than an int in your id field is problematic. So,

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

is an issue. Simple fix is,

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

but that is kind of dirty and hard to read for another programmer coming in to maintain code. I would advise taking the time to declare a variable just to temporarily store the token you are eventually going to duplicate into your struct.

Astormooke
  • 71
  • 6