Chris
Chris

Reputation: 193

Read input in reverse order

I am new to C. I have just learned pointers and struct.I am trying to modify the following program so that each student read is inserted at the front of the list of students, not at the end. How can I achieve it?

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

#define MAX_LINE_LENGTH 80      // The longest line this program will accept
#define MAX_NUM_STUDENTS 500    // The maximum number of students this program can handle
#define MAX_NAME_SIZE 50        // The maximum allowable name length
typedef struct student_s Student;

struct student_s {
    char name[MAX_NAME_SIZE];
    int age;
    Student* next;              // Pointer to next student in a list
};
Student studentPool[MAX_NUM_STUDENTS];  // The student pool
int firstFree = 0;
Student* newStudent(const char* name, int age)
{
    Student* student = NULL;
    if (firstFree < MAX_NUM_STUDENTS) {
        student = &studentPool[firstFree];
        firstFree += 1;
        strncpy(student->name, name, MAX_NAME_SIZE);
        student->name[MAX_NAME_SIZE - 1] = '\0';  // Make sure it's terminated
        student->age = age;
        student->next = NULL;
    }
    return student;
}
Student* readOneStudent(FILE* file)
{
    char buffer[MAX_LINE_LENGTH];  // Buffer into which we read a line from stdin
    Student* student = NULL;       // Pointer to a student record from the pool

    // Read a line, extract name and age

    char* inputLine = fgets(buffer, MAX_LINE_LENGTH, file);
    if (inputLine != NULL) {        // Proceed only if we read something
        char* commaPos = strchr(buffer, ',');
        if (commaPos != NULL) {
            int age = atoi(commaPos + 1);
            *commaPos = '\0';  // null-terminate the name
            student = newStudent(buffer, age);
        }
    }
    return student;
}
Student* readStudents(FILE *file)
{
    Student* first = NULL;     // Pointer to the first student in the list
    Student* last = NULL;      // Pointer to the last student in the list
    Student* student = readOneStudent(file);
    while (student != NULL) {
        if (first == NULL) {
            first = last = student;   // Empty list case
        } else {
            last->next = student;
            last = student;
        }
        student = readOneStudent(file);
    }
    return first;
}
void printOneStudent(Student student)
{
    printf("%s (%d)\n", student.name, student.age);
}
void printStudents(const Student* student)
{
    while (student != NULL) {
        printOneStudent(*student);
        student = student->next;
    }
}
int main(void)
{
    FILE* inputFile = fopen("studlist.txt", "r");
    if (inputFile == NULL) {
        fprintf(stderr, "File not found\n");
    } else {
        Student* studentList = readStudents(inputFile);
        printStudents(studentList);
    }
}

Upvotes: 0

Views: 185

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754280

You currently have this code to insert at the end (of a non-empty list):

if (first == NULL) {
    first = last = student;   // Empty list case
} else {
    last->next = student;
    last = student;
}

To insert at the front of a non-empty list, you simply need to make the new student into the first student each time, by making its next pointer point to the current first student, and making the first pointer point at the new student.

if (first == NULL) {
    first = last = student;   // Empty list case
} else {
    student->next = first;
    first = student;
}

Draw the boxes; connect them with arrows. It should become obvious.


Also, you could simply use:

student->next = first;
first = student;

If first is null, student->next will be (re)set to null, so there's no need for a special case on first. Since last was only used within the function for adding to the end of the list, when inserting at the front, there's no need for last at all. These two observations make the code still simpler than the first version proposed.

Upvotes: 4

Related Questions