Bugman Huang Bugman Huang - 13 days ago 6
C Question

Linked list issue from reading a file c

I try to design a linked list from a file, but there's some problem when setting the 'first node' of the linked list. The data structure of the linked list is shown as the attached picture below:
Data structure of linled list

In my code, I put two type of structures, one for name, another for score, as below:

typedef struct nodeScore{

int score;
struct nodeScore* nextScore;

}nodeScore;

typedef struct nodeName{

char* firstName;
char* lastName;

nodeScore* nextScore;
struct nodeName* nextName;

}nodeName;


And there's a function to read the score from file line by line, (each line contains 'First name', 'Last name' and up to 4 'scores'), and return the head of linked list:

nodeName* storeFile(const char* fileName, nodeName* nodeN){

FILE *pFile = fopen(fileName, "r");

char input[512];

char* firstName;
char* lastName;
int score;

int line=0;

nodeName* prevName;
nodeScore* prevScore;

while(fgets(input, 512, pFile)){

printf("Line %d now.\n", ++line);

nodeName* ptrN = (nodeName*)malloc(sizeof(nodeName));//allocate for new node name.

firstName = strtok(input, " ");//first space for first name.
ptrN->firstName = firstName;

lastName = strtok(NULL, " ");//second space for last name.
ptrN->lastName = lastName;

if(line == 1){
prevName = ptrN;
nodeN = ptrN;//allocate nodeN the return value to the first line, first node of the linked list.

}else{
prevName->nextName = ptrN;
prevName = ptrN;

}


ptrN->nextName = NULL;
ptrN->nextScore = NULL;

while(score = atoi(strtok(NULL, " \n"))){//store multiple scores until next char is space or next new line.

if(ptrN->nextScore == NULL){//if no link to another score.
nodeScore* ptrS = (nodeScore*)malloc(sizeof(nodeScore));//allocate for new score node.

ptrN->nextScore = ptrS;
ptrS->score = score;
ptrS->nextScore = NULL;
prevScore = ptrS;//record latest 'tail' of linked list.


}else{
nodeScore* ptrS = (nodeScore*)malloc(sizeof(nodeScore));

prevScore->nextScore = ptrS;
ptrS->score = score;
ptrS->nextScore = NULL;
prevScore = ptrS;//record latest 'tail' or linked list.

}


}//done the loop for storing multi-scores.

}//done the loop for reading lines from file.

return nodeN;
}


And finally the main function:

int main(){
char file1[]={"HW5_26.txt"};
nodeName* n1;

printf("\nStart reading file '%s' and store it into linked-list.\n\n", file1);

n1 = storeFile(file1, n1);

printf("%s", n1->firstName);//try to see who's the first person(1st node, should be Albert Einstein), here is when I'm confused.

return 0;
}


In the end of my return value, I alway get the result of 'Sarah' the last node, however, I already set an 'if filter' to make the return value only from the 1st line of data, I don't know which part went wrong, I'll be so appreciate if anyone can give me some advice or idea, thank you.

The txt file is like this:

Albert Einstein 52 67 63
Steve Abrew 90 86 90 93
David Nagasake 100 85 93 89
Mike Black 81 87 81 85
Andrew Dijkstra 90 82 95 87
Joanne Nguyen 84 80 95 91
Chris Walljasper 86 100 96 89
Fred Albert 70 68
Dennis Dudley 74 79 77 81
Leo Rice 95
Fred Flinstone 73 81 78 74
Frances Dupre 82 76 79
Dave Light 89 76 91 83
Hua Tran 91 81 87 94
Sarah Trapp 83 98 94 93


And my headers:

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

Answer

The problem is how you use strtok and the returned pointer:

firstName = strtok(input, " ");//first space for first name.
ptrN->firstName = firstName;

The pointer firstName will be a pointer into the array input. And the array input is the same for the whole loop meaning all pointers for all names will be pointing to the same array. What it also means is that those pointers will become invalid as soon as the storeFile function returns, as the array will no longer exist, and using those pointers will lead to undefined behavior.

There are two possible solutions: One is to use e.g. strdup to duplicate the strings. The other is to have arrays in the structure for the names, and copy the strings.

Note that strdup is not a standard C function, but just about all systems have it. Also note that it will dynamically allocate memory with malloc, so you you need to free the strings before you free the nodes.

Comments