Search code examples
cdoubly-linked-listcircular-list

C linked list insert function creating unwanted entry at the end


I am writing a simple C program and encountered a problem with my code. I am creating a circular linked list data structure and am filling it with data from a text file. Everything seems to work just fine, except that it puts an extra entry at the end of the linked list. Could anyone maybe point out what I am doing wrong and suggest a solution to this problem?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 20
#define MAXLEN 100

//Definition of the structure:
struct list{
    char name[SIZE];
    int min, max;
    struct list *next;
    struct list *prev;
};

typedef struct list List;
typedef List *ListPtr;

//Function prototypes
ListPtr getData(ListPtr lst, ListPtr start);
void print(ListPtr start);

Here's my main():

int main()
{
    ListPtr lst, start;
    lst = (ListPtr) malloc(sizeof(List));
    lst->next = NULL;
    lst->prev = NULL;

    //Gets data from text file
    start = getData(lst, start); //Making start to point to the 1st entry
    print(start);
    system("PAUSE");    
    return 0;
}

Here's the getData():

ListPtr getData(ListPtr lst, ListPtr start){
    //For some reason aditional entry is created with system data in it
    char arr[MAXLEN];
    FILE *data = fopen("data.txt", "r");
    //while(fgets(arr, MAXLEN, data)){
        strcpy(lst->name, strtok(arr, " "));
        lst->min = atoi(strtok(NULL, " "));
        lst->max = atoi(strtok(NULL, " "));
        lst->next = (ListPtr)malloc(sizeof(List));
        lst->next->prev = lst;
        lst = lst->next;
    }
    fclose(data);
    start = lst; //start = end of the list
    while(lst->prev != NULL)
        lst = lst->prev; //goes to the start of the list
    start->next = lst;
    lst->prev = start;
    start = lst;
    return start;
}

And here's a function to check the entries of the list:

void print(ListPtr start){
    int i;
    for(i = 0; i < 9; i++){
        printf("%s %d %d\n", start->name, start->min, start->max);
        start = start->next;
    }
}

The sample of data.txt:

John 10 15
Mike 13 17
Anna 18 23

I want to create this list in circular fashion, so that later I could randomly select entries from it with generating a large number with rand(); and scroll through the list, as it gives the rand() more randomness. Any help with my problem is highly appreciated.

Edit Changing the line in getData(); after fclose(data) to start = lst->prev; seems to have fixed the issue, but it doesn't seem right. Does this still create an unwanted entry and i just remove it from the list making it pollute the memory, or this is was just my logic mistake and it's the right way to fix it?


Solution

  • I advice you to keep the head of the list in a variable, let's call it head. You can solve your problem with:

    int getData(ListPtr *head, char *filename){
       ListPtr lst;
       int count = 0;
       char arr[MAXLEN];
       FILE *data = fopen(filename, "r");
    
       if (data == NULL)
          return -1;
    
       *head = (ListPtr)malloc(sizeof(List));
       lst = *head;
       while(fgets(arr, MAXLEN, data)){
           count++;
           strcpy(lst->name, strtok(arr, " "));
           lst->min = atoi(strtok(NULL, " "));
           lst->max = atoi(strtok(NULL, " "));
           if (!feof(data))
           {
               lst->next = (ListPtr)malloc(sizeof(List));
               lst->next->prev = lst;
               lst = lst->next;
           }
       }
    
       fclose(data);
    
       if (count == 0)
       {
           free(*head);
           return -1;
       }
    
       lst->next = *head;
       (*head)->prev = lst;
    
       return count;
    }
    

    So, in head you will have NULL in the case of empty file and the function returns -1 in case of errors. When the file exists and it is not empty it returns the number of elements in the list and head will be the pointer of the head of the list.

    You should call this function with:

    ListPtr head;
    int nEl;
    
    nEl = getData(&head, "data.txt");