Hi everyone,
I'm working on an assignment that takes a record of student ID, student last and first name and their score, using array of pointers, qsort to sort in alphabetical order, typedef structs, malloc and calloc, etc. and the program prompts those records and it is stored in dynamic memory. This means that it is stored in a dynamically-allocated structure & the address of that structure is stored in the dynamic array of pointers. After that, the program will continue to prompt until the user enters a EOF key to return to the main menu and will have the option to display those records.
The error in my code that I'm trying to fix is that after I enter a valid record the second time through and return to the main menu using EOF key and try to display it, it will get a segmentation fault. However, there is no error when I enter and display only one valid record.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define NAMESIZE 20
#define BLOCK 20
#define BUFSIZE 512
typedef struct {
char last[NAMESIZE];
char first[NAMESIZE];
} name;
typedef struct {
int id;
name name;
int score;
} record;
typedef struct {
record **data;
size_t nalloc;
size_t nused;
} record_list;
void list_init(record_list *list);
void list_destroy(record_list *list);
int list_insert(record_list *list, const record *rec);
int prompt_records(record *rec);
void insert_records(record_list *list);
int cmp_name(const void *p, const void *q);
int cmp_ID(const void *p, const void *q);
void display_ID(record_list *list);
void display_name(record_list *list);
int main(void) {
char input[BUFSIZE];
int choice = 0;
record_list * list = (record_list *) malloc(sizeof(record_list));
if(list->data == NULL) {
fprintf(stderr, "No memory allocated.\n");
}
list_init(list);
printf("------------------\n");
printf("Starting program\n");
printf("------------------\n");
while(1) {
fprintf(stderr, "\n1. Enter records\n");
fprintf(stderr, "2. Display records by sorted ID\n");
fprintf(stderr, "3. Display records by sorted name\n");
fprintf(stderr, "4. Quit\n");
fprintf(stderr, "Enter selection: ");
if(!fgets(input, BUFSIZE, stdin)) {
clearerr(stdin);
return 0;
}
if(sscanf(input, "%d", &choice) == 1) {
switch (choice) {
case 1:
insert_records(list);
break;
case 2:
display_ID(list);
break;
case 3:
display_name(list);
break;
case 4:
printf("Quitting program...\n");
list_destroy(list);
return 0;
default:
printf("Invalid input. Reenter again.\n");
break;
}
} else {
printf("Invalid input. Reenter again.\n");
}
}
return 0;
}
void list_init(record_list *list) {
size_t nalloc = BLOCK;
size_t nused = 0;
record ** data = (record **) malloc(BLOCK * sizeof(record*));
if(data == NULL) {
fprintf(stderr, "Out of memory\n");
exit(0);
}
list->data = data;
list->nalloc = nalloc;
list->nused = nused;
}
void list_destroy(record_list *list) {
size_t i = 0;
for(i = 0; i < list->nused; i++) {
free(list->data[i]);
#ifdef DEBUG
fprintf(stderr, "@\n");
#endif
}
free(list->data);
#ifdef DEBUG
fprintf(stderr, "@\n");
#endif
}
int list_insert(record_list *list, const record *rec) {
record **temp;
int nused = list->nused;
if(list->nalloc == list->nused) {
temp = realloc(list->data, (list->nalloc + BLOCK) * sizeof(record*));
#ifdef DEBUG
fprintf(stderr, "#\n");
#endif
/* if we cannot allocate temp */
if(temp == NULL) {
fprintf(stderr, "Out of memory\n");
return 0;
}
list->data = temp;
list->nalloc += BLOCK;
}
list->data[nused] = (record*) malloc(sizeof(record));
#ifdef DEBUG
fprintf(stderr, "%\n");
#endif
list->data[nused]->id = rec->id;
strncpy(list->data[nused]->name.last, rec->name.last, NAMESIZE);
strncpy(list->data[nused]->name.first, rec->name.first, NAMESIZE);
list->data[nused]->score = rec->score;
list->nused++;
return 1;
}
int prompt_records(record *rec) {
char tempID[BUFSIZE];
char last[NAMESIZE];
char first[NAMESIZE];
char tempScore[BUFSIZE];
while(1) {
fprintf(stderr, "Enter an ID between 1000000 & 9999999: ");
if(!fgets(tempID, BUFSIZE, stdin)) {
clearerr(stdin);
return 0;
}
if(sscanf(tempID, "%d", &rec->id) == 1) {
if(rec->id == 0) {
return 0;
}
if(rec->id >= 1000000 && rec->id <= 9999999) {
break;
}
}
fprintf(stderr, "Invalid ID format.\n");
}
while(1) {
fprintf(stderr, "Enter a valid last name: ");
if(!fgets(last, NAMESIZE, stdin)) {
clearerr(stdin);
return 0;
}
if(sscanf(last, "%s", rec->name.last) == 1) {
if(strlen(rec->name.last) < NAMESIZE) {
break;
}
}
fprintf(stderr, "Incorrect last name.\n");
}
while(1) {
fprintf(stderr, "Enter a valid first name: ");
if(!fgets(first, NAMESIZE, stdin)) {
clearerr(stdin);
return 0;
}
if(sscanf(first, "%s", rec->name.first) == 1) {
if(strlen(rec->name.first) < NAMESIZE) {
break;
}
}
fprintf(stderr, "Incorrect first name.\n");
}
while(1) {
fprintf(stderr, "Enter a valid score between 0 & 100: ");
if(!fgets(tempScore, BUFSIZE, stdin)) {
clearerr(stdin);
return 0;
}
if(sscanf(tempScore, "%d", &rec->score) == 1) {
if (rec->score >= 0 && rec->score <= 100) {
break;
}
}
fprintf(stderr, "Invalid score.\n");
}
return 1;
}
void insert_records(record_list *list) {
record tempdata;
if(list->data == 0) {
list_init(list);
}
while(prompt_records(&tempdata)) {
list_insert(list, &tempdata);
}
}
int cmp_name(const void *p, const void *q) {
const record *pp = p;
const record *qq = q;
int firstName = strcmp(pp->name.first, qq->name.first);
int lastName = strcmp(pp->name.last, qq->name.last);
if(lastName == 0) {
return firstName;
}
return lastName;
}
int cmp_ID(const void *p, const void *q) {
const record *pp = p;
const record *qq = q;
return (pp->id - qq->id);
}
void display_ID(record_list *list) {
size_t i = 0;
if(list->data == NULL) {
printf("No records to display.\n");
}
qsort(list->data, list->nused, sizeof(record), cmp_ID);
for(i = 0; i < list->nused; i++){
printf("%d", list->data[i]->id);
printf(" %s,", list->data[i]->name.last);
printf(" %s: ", list->data[i]->name.first);
printf("%d\n", list->data[i]->score);
}
}
void display_name(record_list *list) {
size_t i = 0;
if(list->data == NULL) {
printf("No records to display.\n");
}
qsort(list->data, list->nused, sizeof(record), cmp_name);
for(i = 0; i < list->nused; i++){
if(list->data == NULL) {
fprintf(stderr, "No records to display.\n");
}
printf("%d", list->data[i]->id);
printf(" %s,", list->data[i]->name.last);
printf(" %s: ", list->data[i]->name.first);
printf("%d\n", list->data[i]->score);
}
}
Sorry about the messy lines of code but can anyone help me?