Search code examples
clinked-listmallocinfinite-loopfile-handling

Unexpected behavior while reading data into linked list from file


I am trying to read and write data from linked list into a file but am encountering an infinite loop while doing so.

Code:

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

struct Program { //structure to hold information of program
    char p_name[50];    //name of program
    char p_code[10];    //code of program
    char responsible[50];   //person responsible for program
    char r_email[50];   //email of responsible
    struct Program* next;
};

struct Program* inputProgram() {
    struct Program *temp = (struct Program*)malloc(sizeof(struct Program));
    printf("Enter the name of program: \n");
    scanf("%s", temp->p_name);
    printf("Enter the code of program: \n");
    scanf("%s", temp->p_code);
    printf("Enter the responsible of program: \n");
    scanf("%s", temp->responsible);
    printf("Enter the email of responsible: \n");
    scanf("%s", temp->r_email);
    return temp;
}

struct Program* addProgram(struct Program* head) {
    struct Program *temp = (struct Program*)malloc(sizeof(struct Program));
    temp = inputProgram();
    temp->next = NULL;
    if (head == NULL) {
        head = temp;
    }
    else {
        temp->next = head;
        head = temp;
    }
    return temp;
}

void write_to_file(struct Program* p) {
    FILE *of;
    of= fopen ("program.txt", "w");
    struct Program* temp = p;
    while(temp!=NULL) {
        fwrite (temp, sizeof(struct Program), 1, of);
        temp = temp->next;
    }
    fclose(of);
}

struct Program* read_from_file() {
    FILE *in;
    struct Program* head;
    struct Program* temp = (struct Program*)malloc(sizeof(struct Program));
    in = fopen ("program.txt", "r");
    while(fread((temp), sizeof(struct Program), 1, in)) {
        if (head == NULL) {
            head = temp;
            head->next = NULL;
        }
        else {
            temp->next = head;
            head = temp;
        }
    }
    fclose (in);
    return head;
}

int main() {
    struct Program *head = NULL;
    head = addProgram(head);
    head = addProgram(head);
    write_to_file(head);
    struct Program *temp = read_from_file();
    while(temp!=NULL){
        printf("%s", temp->p_name);
        temp = temp->next;   
    }

}

I keep getting an infinite loop when I try to read to data into the linked list from the file. As far as I understand, the data is being read correctly but as soon as I try to print it. It keeps going into an infinite loop.

I have tried to making change the read_from_file function. using malloc to assign space to head variable. Tried to assign next of head to NULL and tried the same with temp but still doesnt work.

Any idea where the problem is?


Solution

  • There are several issues with your program, but the one that is causing your infinite loop when traversing a list is that read_from_file() only ever allocates one struct Program. It reads each entry from the file into that same structure, and if it reads at least two, then on the second and each subsequent read, the next pointer of that structure is set to point to the structure itself.

    You need to allocate a separate structure object for each entry in the file. If you want to avoid dynamically allocating and then freeing one extra, then you can use an automatically allocated structure for the initial read, and then make a dynamically-allocated copy after the fact if the read was successful. Example:

    struct Program *read_from_file(void) {
        struct Program *head = NULL;
        FILE *in = fopen("program.txt", "r");
    
        if (in) {
            struct Program prog;
    
            while(fread(&prog, sizeof(prog), 1, in)) {
                struct Program *temp = malloc(sizeof *temp);
                if (!temp) {
                    break;
                }
    
                *temp = prog;
                temp->next = head;
                head = temp;
            }
    
            fclose(in);
        }
    
        return head;
    }
    

    Note also that, as the above demonstrates, there is no need for a special case for the first node. You should, however, check that your function calls succeed, as the above demonstrates with fopen() and malloc(), so as to handle failures gracefully.