Created
November 18, 2018 17:34
-
-
Save cms-codes/7d1314ac3851786660446bd6141485dc to your computer and use it in GitHub Desktop.
Solution using structures and linked list
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/********* Lab6 ******* | |
* Course: PROG1955-1 | |
* Title: Lab 6 | |
* Purpose: Store the last name and first name of students in a dynamic | |
* structure using a linked list | |
* Date: 2018-11-10 | |
* Author: Christopher Slothouber | |
* File: Lab6.c | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
// INPUT_LEN must be large enough to acquire a full line of console input | |
// via fgets, therefore at least n+1, where n is the maximum number of | |
// characters to be read at one time (not including '\r' and/or '\0'). | |
#define INPUT_LEN 50 | |
// NAME_LEN is the length of each name, not including the null terminator. | |
#define NAME_LEN 20 | |
// Common helper functions | |
/********* GetInput ******* | |
* Gets a series of characters from the user via the console and stores | |
* the input in the input array for further processing. | |
* Inputs: a pointer to the first element of an initialized char array. | |
* Outputs: none. | |
*/ | |
void GetInput(char input[]); | |
/********* GetName ******* | |
* Reads up to NAME_LEN characters, including spaces. | |
* Inputs: a pointer to the first element of an initialized char array. | |
* Outputs: none. | |
*/ | |
void GetName(char arrName[]); | |
/********* GetValue ******* | |
* Reads a single integer value from the console into the supplied pointer. | |
* Inputs: an integer pointer. | |
* Outputs: none. | |
*/ | |
void GetValue(int *value); | |
/********* GetInput ******* | |
* Gets a series of characters from the user via the console and stores | |
* the input in the input array for further processing. | |
* Inputs: a pointer to the first element of an initialized char array. | |
* Outputs: none. | |
*/ | |
void GetInput(char input[]) | |
{ | |
// Input is read from the console into a temporary input[] array. | |
// This array is then passed on to sscanf_s() for processing. | |
fgets(input, INPUT_LEN, stdin); | |
return; | |
} | |
/********* GetName ******* | |
* Reads up to NAME_LEN characters, including spaces. | |
* Inputs: a pointer to the first element of an initialized char array. | |
* Outputs: none. | |
*/ | |
void GetName(char arrName[]) | |
{ | |
int ret = 0; | |
int len = 0; | |
// INPUT_LEN must be large enough to acquire a full line of console input | |
// via fgets, therefore at least n+1, where n is the maximum number of | |
// characters to be read at one time (not including '\r' and/or '\0'). | |
// This input array is a temporary buffer processed by sscanf_s(). | |
char input[INPUT_LEN] = { 0 }; | |
printf("Please enter up to %d characters\n", NAME_LEN); | |
do | |
{ | |
printf(" : "); | |
// Calling fgets() - but this could be any other input method. | |
GetInput(&input[0]); | |
// Read in a string from the input acquired via GetInput() | |
// sscanf_s() returns 1 when successful | |
ret = sscanf_s(input, "%20c", arrName, NAME_LEN); | |
} while (ret = 0); | |
// By reading in characters instead of a string, we allow names with | |
// spaces. But the side-effect is \n newline is also read. So here we | |
// get rid of the newline. The null terminator is taken care of in the | |
// strBuf[] array in the main() loop. | |
len = strlen(arrName); | |
if (arrName[len - 1] == '\n') | |
arrName[len - 1] = 0; | |
return; | |
} | |
/********* GetValue ******* | |
* Reads a single integer value from the console into the supplied pointer. | |
* Inputs: an integer pointer. | |
* Outputs: none. | |
*/ | |
void GetValue(int *value) | |
{ | |
int ret = 0; | |
// INPUT_LEN must be large enough to acquire a full line of console input | |
// via fgets, therefore at least n+1, where n is the maximum number of | |
// characters to be read at one time (not including '\r' and/or '\0'). | |
// This input array is a temporary buffer supplied to sscanf(). | |
char input[INPUT_LEN] = { 0 }; | |
do | |
{ | |
printf(" : "); | |
// Calling fgets() - but this could be any other input method. | |
GetInput(&input[0]); | |
// Read in an integer from the input acquired via GetInput() | |
// sscanf_s() returns 1 when successful | |
ret = sscanf_s(input, "%d", value); | |
} while (ret = 0); | |
return; | |
} | |
// Define the structure that will hold the necessary fields for each student | |
// record. | |
struct studentRecord | |
{ | |
char *firstName; | |
char *lastName; | |
struct studentRecord *nextPtr; | |
}; | |
typedef struct studentRecord StudentRecord; | |
/********* createRecord ******* | |
* Created a record (struct) using the supplied character pointers. This | |
* function allocates dedicated memory for the struct and character fields. | |
* Inputs: a char pointer to a first name and a char pointer to a last name. | |
* Outputs: a pointer to an allocated StudentRecord type (struct). | |
*/ | |
StudentRecord * createRecord(char *firstName, char *lastName); | |
/********* printRecord ******* | |
* Prints out the fields associated with this StudentRecord. | |
* Inputs: a pointer to a StudentRecord struct. | |
* Outputs: none. | |
*/ | |
void printRecord(StudentRecord *r); | |
/********* insertRecord ******* | |
* Appends a record to the linked list. | |
* Inputs: a pointer to the first struct in a linked list, | |
* a pointer to a StudentRecord type (struct). | |
* Outputs: none. | |
*/ | |
void insertRecord(StudentRecord **headPtr, StudentRecord *r); | |
/********* listRecords ******* | |
* Displays the details for reach record in the StudentRecords linked list. | |
* Inputs: a pointer to the first struct in a linked list. | |
* Outputs: none. | |
*/ | |
void listRecords(StudentRecord **headPtr); | |
/********* freeRecords ******* | |
* Empties the list of all records, freeing the allocated memory. | |
* Inputs: a pointer to the first struct in a linked list. | |
* Outputs: none. | |
*/ | |
void freeRecords(StudentRecord **headPtr); | |
StudentRecord * createRecord(char *firstName, char *lastName) | |
{ | |
StudentRecord *r = malloc(sizeof(StudentRecord)); | |
if (r == NULL) | |
{ | |
puts("Could not allocate memory!"); | |
exit(-1); | |
} | |
char *fN = NULL; | |
char *lN = NULL; | |
// strdup() calls malloc() | |
fN = _strdup(firstName); | |
lN = _strdup(lastName); | |
if (fN == NULL || lN == NULL) | |
{ | |
puts("Could not allocate memory!"); | |
exit(-1); | |
} | |
r->firstName = fN; | |
r->lastName = lN; | |
r->nextPtr = NULL; | |
return r; | |
} | |
void printRecord(StudentRecord *r) | |
{ | |
printf("First name: %s, Last name: %s\n", r->firstName, r->lastName); | |
} | |
void insertRecord(StudentRecord **headPtr, StudentRecord *r) | |
{ | |
StudentRecord *previousPtr = NULL; | |
StudentRecord *currentPtr = *headPtr; | |
// Find the last item in the list. | |
while (currentPtr != NULL) | |
{ | |
previousPtr = currentPtr; | |
currentPtr = currentPtr->nextPtr; | |
} | |
if (previousPtr == NULL) | |
// This is the first record to be added to the list. | |
{ | |
r->nextPtr = *headPtr; | |
*headPtr = r; | |
} | |
else | |
{ | |
// Append the new item to the end of the list, with the | |
// last item becoming the second-last item. | |
previousPtr->nextPtr = r; | |
r->nextPtr = currentPtr; | |
} | |
return; | |
} | |
void listRecords(StudentRecord **headPtr) | |
{ | |
StudentRecord *currentPtr = NULL; | |
int counter = 0; | |
currentPtr = *headPtr; | |
if (currentPtr == NULL) | |
// No records in this list. | |
{ | |
puts("Empty."); | |
return; | |
} | |
do | |
{ | |
printRecord(currentPtr); | |
currentPtr = currentPtr->nextPtr; | |
counter++; | |
} while (currentPtr != NULL); | |
printf("%d records listed.\n", counter); | |
puts("End of list."); | |
return; | |
} | |
void freeRecords(StudentRecord **headPtr) | |
{ | |
StudentRecord *currentPtr = NULL; | |
StudentRecord *nextPtr = NULL; | |
currentPtr = *headPtr; | |
if (currentPtr == NULL) | |
// No records in this list. | |
{ | |
return; | |
} | |
do | |
{ | |
// Keep track of the next record in the list. | |
nextPtr = currentPtr->nextPtr; | |
// Free all allocated memory - first the struct members, | |
// then the struct itself. | |
free(currentPtr->firstName); | |
free(currentPtr->lastName); | |
free(currentPtr); | |
// Advance to the next item in the list. | |
currentPtr = nextPtr; | |
} while (currentPtr != NULL); | |
} | |
int main() | |
{ | |
int numStudents = 0; | |
// Temporary buffers to hold input - these are copied to an allocated portion of | |
// memory for each name when creating the record in createRecord(). | |
char fBuf[NAME_LEN + 1] = { 0 }; | |
char lBuf[NAME_LEN + 1] = { 0 }; | |
// This is the pointer to the first record in our list. | |
StudentRecord *headPtr = NULL; | |
puts("PROG1955 Lab 6 - A program to store and display first and last names of students"); | |
puts("Please enter the number of students"); | |
// Prompt for the size of the class. | |
GetValue(&numStudents); | |
for (int i = 0; i < numStudents; i++) | |
{ | |
// First we zero out our temporary first and last names buffer arrays. | |
memset(fBuf, 0, NAME_LEN + 1 * sizeof(char)); | |
memset(lBuf, 0, NAME_LEN + 1 * sizeof(char)); | |
// Now we get the first and last name. | |
printf("Please enter the first name for student #%d:\n", i + 1); | |
GetName(fBuf); | |
printf("Please enter the last name for student #%d:\n", i + 1); | |
GetName(lBuf); | |
// Record is appended to the list. | |
insertRecord(&headPtr, createRecord(fBuf, lBuf)); | |
} | |
puts("Student records listing:"); | |
listRecords(&headPtr); | |
printf("Freeing allocated memory... "); | |
freeRecords(&headPtr); | |
puts("Done."); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment