'Why is my Professor's Linked List Printing Backwards?

I have a project that I'm working on for a Systems Programming course. I'm building off of my professor's code. (Please don't mind her lack of labelling, etc. - I'm gonna try to clean this up as best as I can.)

Does anybody know why her linked list code is printing backwards?

Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
    
struct Node {
    char name[15];
    char title[15];
    int year;
    struct Node *next;
    struct Node *prev;
};
    
typedef struct Node *Box;
    
Box print_list(Box pointer);
Box insert_node(FILE *inputp);
    
int main() {
    Box head = NULL, temp;
    FILE *inputp, *outputp;
    int i;
    
    inputp = fopen("input.txt", "r");
    
    outputp = fopen("output.txt", "w");
    
    head = insert_node(inputp);
        
    for (i = 0; i < 4; i++) {
        temp = insert_node(inputp);
        temp->next = head;
        head = temp;
    }
        
    print_list(head);
    return 0;
}
    
Box print_list(Box pointer) {
    
    Box here = pointer;
    
    while (here != NULL) {
    
        printf("%s, %s, %d \n", here->name, here->title, here->year);
        here = here->next;  
    }
    
    return pointer;
}
    
Box insert_node(FILE *inputp) {
    
    Box temp = NULL;
    
    temp = (Box)malloc(sizeof(struct Node));
    
    fscanf(inputp, "%s", &temp->name);
    fscanf(inputp, "%s", &temp->title);
    fscanf(inputp, " %d", &temp->year);
    
    temp->next = NULL;
    temp->prev = NULL;
        
    return temp;
}

This program's purpose is to read a .txt file "playlist" of songs and create a linked list out of them. The input is:

Rachmaninov Concerto_No_2 1999
Mozart Symphony_No_41 2000
Vivaldi The_Seasons 2003 
Beethoven Symphony_No_5 1994
Bach Toccatas 2005

While the program outputs:

Bach, Toccatas, 2005 
Beethoven, Symphony_No_5, 1994 
Vivaldi, The_Seasons, 2003 
Mozart, Symphony_No_41, 2000 
Rachmaninov, Concerto_No_2, 1999

(I also don't know why she included an output file in the code, all of the output is in the console, not stored in a file. Ignore that.)



Solution 1:[1]

The list prints in reverse order because you insert each new node at the beginning of the list. You should use a tail pointer to keep track of the end of the list.

Also note these remarks:

  • both the next and the prev links should be updated.

  • hiding pointers behind typedefs as in typedef struct Node *Box; is considered bad practice because it is confusing and error prone.

  • insert_node is a confusing name for a function that merely allocates a new node from file data.

  • insert_node should test if fscanf() succeeded at reading the data

  • fscanf(inputp, "%s", &temp->name); has undefined behavior if the name of the composer exceeds 14 bytes. The same applies to the title. The maximum number of characters to store into the destination arrays before the null terminator should be specified as %14s and these arrays should be defined with a larger length.

  • main should check if a node was successfully allocated and initialized from file data. Instead of hardcoding the number of nodes, one should iterate as long as nodes can be read from the file.

Here is a modified version:

#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
    
struct Node {
    char name[40];
    char title[40];
    int year;
    struct Node *next;
    struct Node *prev;
};
    
void print_list(const Node *pointer);
Node *read_node(FILE *inputp);
    
int main() {
    Node *head = NULL;
    Node *tail = NULL;
    Node *node;
    FILE *inputp, *outputp;
    int i;

    inputp = fopen("input.txt", "r");
    if (!inputp) {
       fprintf(stderr, "cannot open input.txt: %s\n", strerror(errno));
       return 1;
    }
    outputp = fopen("output.txt", "w");
    if (!outputp) {
       fprintf(stderr, "cannot open output.txt: %s\n", strerror(errno));
       return 1;
    }
    
    while ((node = read_node(inputp)) != NULL) {
        if (!head) {
            head = tail = node;
        } else {
            node->prev = tail;
            tail = tail->next = node;
        }
    }
        
    print_list(head);

    // should free node list

    return 0;
}
    
void print_list(const Node *pointer) {
    while (pointer != NULL) {
        printf("%s, %s, %d\n", pointer->name, pointer->title, pointer->year);
        pointer = pointer->next;  
    }
}
    
Node *read_node(FILE *inputp) {
    Node *temp = malloc(sizeof(*temp));
    
    if (temp != NULL
    &&  fscanf(inputp, "%39s%39s%d", &temp->name, &temp->title, &temp->year) == 3) {
        temp->next = NULL;
        temp->prev = NULL;
        return temp;
    } else {
        free(temp);
        return NULL;
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1