The following program displays a menu, and prompts the user to choose an option. Options include to add a book, delete a book, view all books, and to exit the program. (Note that the actual code to implement the database functions will be added later.)
The program files were compiled with no error messages or warnings using the following command line...
$gcc -std=c99 -Wall -Wextra -Wpedantic main.c screen.c input.c database.c -o books
I would like your feedback on any potential issues, along with any improvements that can be made to the code.
Here are the files:
main.c
#include <stdio.h>
#include <stdlib.h>
#include "struct.h"
#include "screen.h"
#include "input.h"
#include "database.h"
/* display main menu and prompt user to choose menu option */
int main(int argc, char *argv[])
{
if (argc != 1)
{
fprintf(stderr, "Usage: %s\n", argv[0]);
exit(EXIT_FAILURE);
}
/* name of file to store data in */
const char dataFile[] = "database.bin";
/* array of structs containing menu options (number, text, and function) */
menuStruct menuArray[] = {
{ 1, "Add book", addBook },
{ 2, "Delete book", deleteBook },
{ 3, "View all books", viewAllBooks }
};
/* number of menu items */
int menuArrayLength = sizeof(menuArray)/sizeof(menuArray[0]);
int menuChoice;
void(*menuFunction)(const char fname[]);
/* prompt user to choose menu option */
while (1)
{
clearScreen();
displayMainMenu(menuArray, menuArrayLength);
menuChoice = getMenuChoice();
if (menuChoice == (menuArrayLength + 1))
{
clearScreen();
exit(EXIT_SUCCESS);
}
menuFunction = getMenuFunction(menuChoice, menuArray, menuArrayLength);
if (menuFunction != NULL)
{
menuFunction(dataFile);
}
else
{
fprintf(stderr, "\n Invalid entry, press ENTER to continue");
flushInput();
}
}
return 0;
}
struct.h
#ifndef STRUCT_H
#define STRUCT_H
#define MAXSTRLEN 50 /* max length for string */
/* struct to hold a menu choice (number, text, and function) */
typedef struct menuStruct
{
int menuChoice;
char menuText[MAXSTRLEN];
void (*menuFunction)(const char *fname);
} menuStruct;
/* struct to hold details of a book */
typedef struct bookStruct
{
char id[MAXSTRLEN];
char title[MAXSTRLEN];
char author[MAXSTRLEN];
double price;
} bookStruct;
#endif
screen.h
#ifndef SCREEN_H
#define SCREEN_H
#include "struct.h"
/* displayMainMenu(): display the main menu using menuArray where each element in the array
is a struct containing a menu choice (number, text, and function), except the exit option */
void displayMainMenu(const menuStruct menuArray[], const int menuArrayLength);
/* displayAddBookHeader(): display the header for adding a book */
void displayAddBookHeader();
/* displayDeleteBookHeader(): display the header for deleting a book */
void displayDeleteBookHeader();
/* displayViewAllBooksHeader(): display the header for viewing all books */
void displayViewAllBooksHeader();
/* clearScreen(): clear the screen */
void clearScreen();
#endif
screen.c
#include <stdio.h>
#include "screen.h"
void displayMainMenu(const menuStruct menuArray[], const int menuArrayLength)
{
printf(" \n"
"=============================================================================\n"
" Database for Book Collection \n"
" Menu Choices \n"
"=============================================================================\n");
for (int i = 0; i < menuArrayLength; i++)
{
printf("\n %d. %s", menuArray[i].menuChoice, menuArray[i].menuText);
}
printf("\n %d. Exit\n", menuArrayLength + 1); /* exit option for main menu */
}
void displayAddBookHeader()
{
printf(" \n"
"=============================================================================\n"
" Database for Book Collection \n"
" Add Book \n"
"=============================================================================\n");
}
void displayDeleteBookHeader()
{
printf(" \n"
"=============================================================================\n"
" Database for Book Collection \n"
" Delete Book \n"
"=============================================================================\n");
}
void displayViewAllBooksHeader()
{
printf(" \n"
"=============================================================================\n"
" Database for Book Collection \n"
" View All Books \n"
"=============================================================================\n");
}
void clearScreen()
{
printf("\x1b[2J\x1b[1;1H");
}
input.h
#ifndef INPUT_H
#define INPUT_H
#include "struct.h"
/* getMenuChoice(): prompt user to enter menu choice and return choice */
int getMenuChoice();
/* getMenuFunction(): search each struct within menuArray for option matching menuChoice and return corresponding function */
void(*getMenuFunction(const int menuChoice, const menuStruct menuArray[], const int size))(const char fname[]);
/* flush input from buffer */
void flushInput();
#endif
input.c
#include <stdio.h>
#include <string.h>
#include "input.h"
#define MAXSTRLEN 50
int getMenuChoice()
{
printf("\n Enter Choice: ");
char userInput[MAXSTRLEN], junk[MAXSTRLEN];
int menuChoice;
fgets(userInput, sizeof(userInput), stdin);
if (strchr(userInput, '\n') == NULL)
{
flushInput();
return 0;
}
if (sscanf(userInput, "%d%[^\n]", &menuChoice, junk) != 1)
{
return 0;
}
return menuChoice;
}
void(*getMenuFunction(const int menuChoice, const menuStruct menuArray[], const int size))(const char fname[])
{
for (int i = 0; i < size; i++)
{
if (menuChoice == menuArray[i].menuChoice)
return menuArray[i].menuFunction;
}
return NULL;
}
void flushInput()
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
{
/* skip it */;
}
}
database.h
#ifndef DATABASE_H
#define DATABASE_H
void addBook(const char fname[]);
void deleteBook(const char fname[]);
void viewAllBooks(const char fname[]);
#endif
database.c
#include <stdio.h>
#include <stdlib.h>
#include "input.h"
#include "database.h"
void addBook(const char fname[])
{
printf("\n Inside addBook(): fname = %s, press ENTER to continue", fname);
flushInput();
}
void deleteBook(const char fname[])
{
printf("\n Inside deleteBook(): fname = %s, press ENTER to continue", fname);
flushInput();
}
void viewAllBooks(const char fname[])
{
printf("\n Inside viewAllBooks(): fname = %s, press ENTER to continue", fname);
flushInput();
}