I am studing for a test and have this question : Modify this program so that it takes input in a different format:each line consists of an age, a comma, a space and a name, e.g.
23, Angus McGurkinshaw
I understand I need to modify something in readOneStudent function.Not sure how to read the name by knowing the address of comma.Please help.
The input and output should look like this:
input = 21, Fred Nurk
927, Arwen Evensong
output is suppose to be:
Arwen Evensong (927)
Fred Nurk (21)
..
#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
};
// Create a pool of student records to be allocated on demand
Student studentPool[MAX_NUM_STUDENTS]; // The student pool
int firstFree = 0;
// Return a pointer to a new student record from the pool, after
// filling in the provided name and age fields. Returns NULL if
// the student pool is exhausted.
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;
}
// Read a single student from a csv input file with student name in first column,
// and student age in second.
// Returns: A pointer to a Student record, or NULL if EOF or an invalid
// student record is read. Blank lines, or lines in which the name is
// longer than the provided name buffer, or there is no comma in the line
// are considered invalid.
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 {
student -> next = first;
first = student;
}
student = readOneStudent(file);
}
return first;
}
// printOneStudent: prints a single student, passed by value
void printOneStudent(Student student)
{
printf("%s (%d)\n", student.name, student.age);
}
// printStudents: print all students in a list of students, passed
// by reference
void printStudents(const Student* student)
{
while (student != NULL) {
printOneStudent(*student);
student = student->next;
}
}
int main(void)
{
FILE* inputFile = stdin;
if (inputFile == NULL) {
fprintf(stderr, "File not found\n");
} else {
Student* studentList = readStudents(inputFile);
printStudents(studentList);
}
}
Below code should work.
Note that
strchr()
This returns a pointer to the first occurrence of the character c in the string str, or NULL if the character is not found.
I think you were trying to get age from name string.
#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
};
// Create a pool of student records to be allocated on demand
Student studentPool[MAX_NUM_STUDENTS]; // The student pool
int firstFree = 0;
// Return a pointer to a new student record from the pool, after
// filling in the provided name and age fields. Returns NULL if
// the student pool is exhausted.
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;
}
// Read a single student from a csv input file with student name in first column,
// and student age in second.
// Returns: A pointer to a Student record, or NULL if EOF or an invalid
// student record is read. Blank lines, or lines in which the name is
// longer than the provided name buffer, or there is no comma in the line
// are considered invalid.
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);
//printf("age and commaPos is %d,%s \n ",age,commaPos);
char* name = commaPos+1;
name[strcspn(name, "\n")] = 0; //remove /n from fgets
*commaPos = '\0'; // null-terminate the age
int age = atoi(buffer);
//printf("age and commaPos is %d,%s \n ",age,name);
//student = newStudent(buffer, age);
student = newStudent(name, 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 {
student -> next = first;
first = student;
}
student = readOneStudent(file);
}
return first;
}
// printOneStudent: prints a single student, passed by value
void printOneStudent(Student student)
{
printf("%s (%d)\n", student.name, student.age);
}
// printStudents: print all students in a list of students, passed
// by reference
void printStudents(const Student* student)
{
while (student != NULL) {
printOneStudent(*student);
student = student->next;
}
}
int main(void)
{
FILE* inputFile = stdin;
if (inputFile == NULL) {
fprintf(stderr, "File not found\n");
} else {
Student* studentList = readStudents(inputFile);
printStudents(studentList);
}
}
Related
I am learning C and I am currently learning about dynamic memory allocation and linked lists and I ran into a problem. I found this post and followed the answer. However my program is still skipping my first node when being printed out.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct record
{
int id;
char name[257];
float age;
struct record *next;
};
int main(void)
{
int i = 1;
struct record *firstrecord = (struct record *)malloc(sizeof(struct record));
firstrecord->id = 1000;
char firstname[] = "John Doe";
memcpy(firstrecord->name, firstname,strlen(firstname) + 1);
firstrecord->age = 24.5;
firstrecord->next = NULL;
struct record *mostrecentlycreated = firstrecord;
int iyes = 1;
char cyes;
int yes = 1;
while (yes == iyes)
{
// build next node
mostrecentlycreated->next = (struct record *)malloc(sizeof(struct record));
// change data in new record
int newid;
char newname[257];
char temp;
float newage;
char cnewage[257];
printf("Enter the name: ");
fgets(newname,257,stdin);
newid = 1000 + i;
printf("Enter the person's age: ");
fgets(cnewage,257,stdin);
newage = atof(cnewage);
mostrecentlycreated->id = newid;
memcpy(mostrecentlycreated->name,newname,strlen(newname) + 1);
mostrecentlycreated->age = newage;
mostrecentlycreated = mostrecentlycreated->next;
mostrecentlycreated->next = NULL;
i++;
// decide whether or not to keep going
printf("Do you wish to continue? 1\\0 ");
fgets(&cyes,1,stdin);
iyes = atoi(&cyes);
scanf("%c",&temp);
}
struct record *traverse = firstrecord;
while (traverse != NULL)
{
printf("Employee id is %i; Employee Name is %s; Employee Age is %f\n",traverse->id,traverse->name,traverse->age);
traverse = traverse->next;
}
free(firstrecord);
free(mostrecentlycreated);
return 0;
}
And this is my output:
Enter the name: john doe
Enter the person's age: 23
Do you wish to continue? 1\0 0
Employee id is 1001; Employee Name is john doe
; Employee Age is 23.000000
Employee id is 0; Employee Name is ; Employee Age is 0.000000
Why does it not print out the first person?
After you create your first node, your loop is creating a new node on each iteration, but it is assigning the user's input to the previous node in the list, not the current node being added to the list. So, on the 1st iteration, you are overwriting the 1st node's data, and then appending a 2nd empty node. Then on the 2nd iteration, you are overwriting the 2nd node's data, and appending a blank 3rd node. And so on.
Try this instead:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct record
{
int id;
char name[257];
float age;
struct record *next;
};
int main(void)
{
int i = 1;
struct record *firstrecord = (struct record *)malloc(sizeof(struct record));
firstrecord->id = 1000;
strncpy(firstrecord->name, "John Doe", 257);
firstrecord->age = 24.5;
firstrecord->next = NULL;
struct record *mostrecentlycreated = firstrecord;
const int cyes = 1;
int iyes = 1;
while (iyes == cyes)
{
// build next node
struct record *newrecord = (struct record *)malloc(sizeof(struct record));
// change data in new record
newrecord->id = 1000 + i;
printf("Enter the name: ");
fgets(newrecord->name, 257, stdin);
printf("Enter the person's age: ");
scanf("%f", &(newrecord->age));
newrecord->next = NULL;
mostrecentlycreated = newrecord;
++i;
// decide whether or not to keep going
printf("Do you wish to continue? 1\\0 ");
scanf("%d", &iyes);
}
struct record *traverse = firstrecord;
while (traverse != NULL)
{
printf("Employee id is %i; Employee Name is %s; Employee Age is %f\n", traverse->id, traverse->name, traverse->age);
traverse = traverse->next;
}
traverse = firstrecord;
while (traverse != NULL)
{
struct record *nextrecord = traverse->next;
free(traverse);
traverse = nextrecord;
}
return 0;
}
I have a function readPatientDataFromFile that reads data from a file and stores it in a struct. The function should return a pointer that points to the start of a linked list but instead the pointer that is returned points to the end of the list.
Here is the complete implementation of the code:
#include <stdio.h>
#include <stdlib.h>
struct patient
{
char firstname[30];
char lastname[30];
int age;
struct appointment *appointment_details;
struct patient *next;
};
struct patient * readPatientsFromFile(char *filename);
struct patient * appendPatient(struct patient *endPtr, struct patient *newPatient);
int main(){
struct patient *patientPtr;
int i = 1;
char patients_filename[] = "patients.txt";
patientPtr = readPatientsFromFile(patients_filename);
printf("---------------------------\n");
while(patientPtr != NULL){
printf("Patient ID: %d\n", i);
printf("Name: %s %s\n", patientPtr->lastname, patientPtr->firstname);
printf("Age: %d\n", patientPtr->age);
printf("----------------------------\n");
patientPtr = patientPtr->next;
i++;
}
}
struct patient * appendPatient(struct patient *endPtr, struct patient *newPatient){
endPtr->next = newPatient;
return (endPtr->next);
}
struct patient * readPatientsFromFile(char *filename){
FILE *ifile;
ifile = fopen(filename, "r");
struct patient *startPtr = NULL;
struct patient *endOfPatients = NULL;
size_t c;
if (ifile != NULL){
struct patient *patientPtr = (struct patient *) malloc(sizeof(struct patient));
do {
c = fread(patientPtr, sizeof(struct patient), 1, ifile);
// create linked list
if (startPtr == NULL){
startPtr = patientPtr;
endOfPatients = startPtr;
}
else {
endOfPatients = appendPatient(endOfPatients, patientPtr);
}
printf("First Name: %s\n", startPtr->firstname);
}
while(c >= 1);
endOfPatients->next = NULL;
fclose(ifile);
printf("Reading data from file successful!!!\n");
}
else {
printf("Error reading from file");
}
return startPtr;
}
As I understand it, the printf statement in the readPatientsFromFile function should always output the same thing but from the output (attached) below, it seems that the pointer that should point to the start of the list keeps getting updated for each iteration of the loop.
Here's the output of the code:
First Name: John
First Name: Jane
First Name: Lloyd
First Name: Jane
First Name: Jane
First Name: John
First Name: Jane
First Name: Lloyd
First Name: Paulo
First Name: Paulo
Reading data from file successful!!!
---------------------------
Patient ID: 1
Name: Coelho Paulo
Age: 49
----------------------------
I'd like to know why the code is not running as expected. Thanks.
Thanks to #EdmCoff, the problem was that I didn't allocate memory for new nodes in the list with malloc so the data was being assigned to the node each time. The solution was to move the malloc statement into the while loop.
The corrected readPatientsFromFile is given below:
struct patient * readPatientsFromFile(char *filename){
FILE *ifile;
ifile = fopen(filename, "r");
struct patient *startPtr = NULL;
struct patient *endOfPatients = NULL;
size_t c;
struct patient *patientPtr
if (ifile != NULL){
do {
patientPtr = (struct patient *) malloc(sizeof(struct patient)); // corrected portion
c = fread(patientPtr, sizeof(struct patient), 1, ifile);
// create linked list
if (startPtr == NULL){
startPtr = patientPtr;
endOfPatients = startPtr;
}
else {
endOfPatients = appendPatient(endOfPatients, patientPtr);
}
printf("First Name: %s\n", startPtr->firstname);
}
while(c >= 1);
endOfPatients->next = NULL;
fclose(ifile);
printf("Reading data from file successful!!!\n");
}
else {
printf("Error reading from file");
}
return startPtr;
}
I need to read-in a .csv file and print it's contents, the students' names and age. The actual output is correct but it is appended with junk characters. The program also terminates with a segmentation fault! For some reason, these problems do not occur on OSX but do on Windows.
Code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE_LENGTH 80
#define MAX_NUM_STUDENTS 500
#define MAX_NAME_SIZE 50
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];
Student* student = NULL;
char* inputLine = fgets(buffer, MAX_LINE_LENGTH, file);
if (inputLine != NULL) { // Proceed only if we read something
char* commaPos = strchr(buffer, ',');
if (commaPos != NULL && commaPos > buffer) {
int age = atoi(commaPos + 1);
*commaPos = '\0'; // null-terminate the name
student = newStudent(buffer, age);
}
}
return student;
}
int precedes(const Student* new, const Student* old)
{
int final = strcmp(old->name, new->name);
if (final == 0) {
if (old->age <= new->age) {
final = -1;
} else {
final = 1;
}
}
return final;
}
Student* insert(Student* student, Student* list)
{
Student* current = list;
if (list == NULL) {
student->next = list;
list = student;
} else if (precedes(current, student) < 0) {
student->next = current;
current = student;
list = current;
} else {
while(current->next && precedes(student, current->next) < 0) {
current = current->next;
}
student->next = current->next;
current->next = student;
}
return list;
}
Student* readStudents(FILE *file)
{
Student* student_list;
Student* student = readOneStudent(file);
while (student != NULL) {
student_list = insert(student, student_list);
student = readOneStudent(file);
}
return student_list;
}
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);
}
}
input:
Zaphod Beeblebrox,250
Albert Einstein,133
Albert Einstein,7
The output is sorted alphabetically for student names' then increasing age.
expected output:
Albert Einstein (7)
Albert Einstein (133)
Zaphod Beeblebrox (250)
on Windows, output is appended with:
p
# (0)
then segfault.
student_list is a uninitialized stack variable. It could be 0 (NULL) on some machines but that does not have to be true. In general you should expect an initialized stack variable to contain whatever garbage is in that location of memory.
Here is the simple fix:
Student* readStudents(FILE *file)
{
Student* student_list = NULL;
Student* student = readOneStudent(file);
while (student != NULL) {
student_list = insert(student, student_list);
student = readOneStudent(file);
}
return student_list;
}
The bug is triggered in the insertion method here:
if (list == NULL) {
student->next = list;
list = student;
}
Whatever the variable list is pointing to will be used for sorting. In your case it looks like it was "bigger" than all the legit inputs and garbage made its way to the back of your linked list. The print function would then keep dereferencing uninitialized next pointers until the SIGSEGV is triggered.
For debugging this sort of problems you might want to check out valgrind.
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);
}
}
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.
Given the struct I have created below, how would I change the code to make it read from insert (student) rather than from the way it is now. Basically, the code at the moment takes input as a student written as:
student guy,23
and the output will be:
student guy (23)
and this part is working thus far. What the insert (and comes before) code will do is when multiple students are entered, sort them in alphabetical order - or if they have an identical name, by age. I have completed the code to do this but cannot seem to work out how to call it properly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <assert.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
// The declaration of the student record (or struct). Note that
// the struct contains the name as an array of characters, rather than
// containing just a pointer to the name as before.
typedef struct student_s Student;
struct student_s {
char name[MAX_NAME_SIZE];
int age;
Student* next; // Pointer to next student in a list
};
bool comesBefore(const Student* student1, const Student* student2) {
int name_compare = strcmp(student1->name, student2->name);
if (name_compare < 0) {
return true;
}
else if (name_compare == 0) {
int age1 = student1->age;
int age2 = student2->age;
if (age1 < age2) {
return true;
}
}
return false;
}
Student* insert(Student* student, Student* list) {
Student* curr = NULL;
Student* prev = NULL;
if (list == NULL)
return student;
if (comesBefore(student, list)) {
student->next = list;
return student;
}
for (curr = list, prev = NULL;
curr != NULL && comesBefore(student, curr) != true;
prev = curr, curr = curr->next);
assert(prev != NULL);
student->next = curr;
prev->next = student;
return list;
}
// Create a pool of student records to be allocated on demand
Student studentPool[MAX_NUM_STUDENTS]; // The student pool
int firstFree = 0;
// Return a pointer to a new student record from the pool, after
// filling in the provided name and age fields. Returns NULL if
// the student pool is exhausted.
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;
}
// Read a single student from a csv input file with student name in first column,
// and student age in second.
// Returns: A pointer to a Student record, or NULL if EOF or an invalid
// student record is read. Blank lines, or lines in which the name is
// longer than the provided name buffer, or there is no comma in the line
// are considered invalid.
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* cp = fgets(buffer, MAX_LINE_LENGTH, file);
if (cp != NULL) { // Proceed only if we read something
char* commaPos = strchr(buffer, ',');
if (commaPos != NULL && commaPos > buffer) {
int age = atoi(commaPos + 1);
*commaPos = '\0'; // null-terminate the name
student = newStudent(buffer, age);
}
}
return student;
}
// Reads a list of students from a given file. Input stops when
// a blank line is read, or an EOF occurs, or an illegal input
// line is encountered.
// Returns a pointer to the first student in the list or NULL if no
// valid student records could be read.
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;
}
// printOneStudent: prints a single student, passed by value
void printOneStudent(Student student)
{
printf("%s (%d)\n", student.name, student.age);
}
// printStudents: print all students in a list of students, passed
// by reference
void printStudents(const Student* student)
{
while (student != NULL) {
printOneStudent(*student);
student = student->next;
}
}
// Main program. Read a linked list of students from a csv file, then display
// the contents of that list.
int main(void)
{
FILE* inputFile = stdin;
if (inputFile == NULL) {
fprintf(stderr, "File not found\n");
}
else {
Student* studentList = readStudents(inputFile);
printStudents(studentList);
// The program could now do various things that make use of
// the linked list, like deleting students and adding new ones,
// but the program is already quite long enough!
}
}
I believe it requires some sort of edit to readStudents but cannot work out what call change to make regardless of source material I have read.
The key idea is that you need to adjust this:
if (first == NULL) {
first = last = student; // Empty list case
}
else {
last->next = student;
last = student;
}
At present you are putting the new student at the end of the list. Instead you are going to keep the list in a sorted order. In concept you have
Arthur -> Bill -> Dave
and a new record, Charles. So you compare first with Charles, discover Charles is bigger, so go on to Bill, and then eventually hit Dave and now know to insert Charles after Bill and before Dave.
Now have a look at the insert() function. Can you see that this is what it's doing? Walking the list and eventually inserting the record - note how it adjusts the "Bill" to point to the new record, and have the new record point to Dave.