1

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?

  • You can make the data reading more solid by checking `scanf`'s return value, and by restricting the data length it reads, for example `if(scanf("%49s", temp->p_name) != 1) { /* handle error */ }`. If any of the data contains a space, it will fail anyway, and the strings will get out-of-kilter, possibly overflowing the `[10]` sized array. In that case, use `if(scanf(" %49[^\n]", temp->p_name) != 1)` including the leading space. – Weather Vane Mar 05 '23 at 18:46
  • 2
    Please enable compiler warnings. In `read_from_file()` it gives `uninitialized local variable 'head' used`. This is very likely to cause bad behaviour. – Weather Vane Mar 05 '23 at 18:53
  • [This post is relevant](https://stackoverflow.com/questions/27063678/compiler-not-detecting-obviously-uninitialized-variable) because the compiler detects that `head` is not initialized before being used in `read_from_file`. – user3386109 Mar 05 '23 at 18:54
  • @WeatherVane My IDE detects that, but compiling on the command line with `-Wall -Wextra` doesn't detect the problem. What method did you use to see the warning? – user3386109 Mar 05 '23 at 18:56
  • @user3386109 with MSVC default level. – Weather Vane Mar 05 '23 at 18:57
  • @WeatherVane Ah ok, a win for Microsoft :) – user3386109 Mar 05 '23 at 18:58
  • `addProgram()` leaks memory by dynamically allocating memory for a `struct Program`, storing the only pointer to it in `temp`, and then immediately overwriting `temp` with a different pointer returned by `inputProgram`. – John Bollinger Mar 05 '23 at 20:39

1 Answers1

1

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157