Doubly Linked List Database Application in C
This was a project from high school done with a friend that implemented a doubly linked list and used this list to manage a database of school records.
This is the entry point of the program. At launch, it allocates memory for the database and prompts the user for an action.
#include "project.h" COURSE array[255]; //Declare global Variables COURSE* FIRST; COURSE* LAST; char filename[255]; void main(void) { char choice; //Declare Variables int i = 0; BOOLEAN quit = FALSE; FIRST = NULL; //Initialize variables LAST = NULL; for(i = 0; i < 256; i++) InitializeRec(&array[i]); filename[0] = '\0'; i = 0; do //menu open until quit = TRUE { choice = DisplayMainMenu(); //Display Main Menu and Get Main Menu Choice switch(choice) //Menu swithc { case 'o': OpenData(); break; case 'a': AddRec(); break; case 's': SearchData(); break; case 'b': BrowseData(); break; case 'd': printf("\nDelete Record\n"); break; case 'c': CloseData(); break; case 'q': quit = QuitProgram(); break; default: printf("\nError\nPlease enter a valid response.\n"); break; } }while(!quit); return; //Exit the program. }
This header file declares all the functions that will be part of the program.
#ifndef PROJECT_H #define PROJECT_H #define TRUE -1 #define FALSE 0 #include "stdio.h" #include "string.h" #include "stdlib.h" struct RECORD { char number[17]; char title[65]; int credit; int lab; struct RECORD* next; struct RECORD* previous; }; typedef struct RECORD COURSE; typedef int BOOLEAN; void Header(void); void GetEnter(void); void NewDat(void); void OpenData(void); void AddRec(void); void SearchData(void); void BrowseData(void); void EditRec(COURSE*); void DeleteRec(COURSE*); void CloseData(void); BOOLEAN QuitProgram(void); char DisplayMainMenu(void); char GetMainMenuChoice(char*); void InitializeRec(COURSE*); void GetNumber(COURSE*); void GetTitle(COURSE*); void GetCredit(COURSE*); void GetLab(COURSE*); void WriteRec(COURSE*); void ReadRec(COURSE*); void DisplayRec(COURSE*); void LinkRec(COURSE*); void UnlinkRec(COURSE*); extern COURSE array[255]; extern COURSE* FIRST; extern COURSE* LAST; extern char filename[255]; #endif
This function prints out the main menu and was made to make the main program more readable and modular.
#include "project.h" char DisplayMainMenu(void) { char return_value; //Declare return value variable Header(); printf("\nO\tOpen database"); //Display Menu printf("\nA\tAdd new record"); printf("\nS\tSearch for a record"); printf("\nB\tBrowse the database"); printf("\nE\tEdit a Record"); printf("\nD\tDelete a record"); printf("\nC\tClose the database"); printf("\nQ\tQuit\n"); return_value = GetMainMenuChoice("Please enter your choice: "); return(return_value); }
Function to add records to the doubly linked list.
#include "project.h" void AddRec(void) { COURSE course1; //Declare Variables COURSE course2; int i = 0; char prompt_yn; char temp[10]; if(filename[0]) //If database open { Header(); printf("\nAdd Record\n"); EditRec(&course1); //Edit Record and Write record WriteRec(&course1); ReadRec(&course2); DisplayRec(&course2); while(array[i].number[0] != '\0') //Find opening in array i++; RecCpy(&array[i], &course2); //Put record in opening LinkRec(&array[i]); //Link new record printf("\nNew record added sucessfully!"); } else{ printf("\nError\nNo database is open.\n"); //Error if no database is open while(1){ //Ask the user if they would like to make one printf("\nWould you like to create a new database? [y/n] "); fgets(temp, 10, stdin); if(strlen(temp) > 2) printf("\nERROR: INVALID RESPONSE LENGTH\n"); else prompt_yn = temp[0]; if(prompt_yn == 'y'){NewDat(); AddRec();} else if(prompt_yn == 'n') break; else{ printf("\nERROR: INVALID RESPONSE\n"); } } } GetEnter(); return; }
This function gives the user the ability to view the records contained in the doubly linked list in order.
#include "project.h" void BrowseData(void) { BOOLEAN quit = FALSE; //Declare Variables BOOLEAN flag = FALSE; COURSE* current; char buff[255]; if(FIRST) //If database is open with atleast 1 record { Header(); printf("\nBrowse the Database\n"); current = FIRST; while(!quit) //Display records until q is pressed { flag = FALSE; DisplayRec(current); if(current == FIRST && current != LAST && !flag) { printf("\nN %8s", "Next"); printf("\nD %8s\tE %8s", "Delete", "Edit"); printf("\nQ %8s\n", "Quit"); fgets(buff, 255, stdin); buff[0] = tolower(buff[0]); if(buff[1] == '\n') { switch(buff[0]) { case 'n': current = current -> next; break; case 'd': DeleteRec(current); quit = TRUE; break; case 'e': UnlinkRec(current); EditRec(current); LinkRec(current); quit = TRUE; break; case 'q': quit = TRUE; break; default: printf("\nError\nPlease enter a valid response.\n"); } } else printf("\nError\nPlease enter a valid response.\n"); flag = TRUE; } if(current == FIRST && current == LAST && !flag) { printf("\nD %8s\tE %8s", "Delete", "Edit"); printf("\nQ %8s\n", "Quit"); fgets(buff, 255, stdin); buff[0] = tolower(buff[0]); if(buff[1] == '\n') { switch(buff[0]) { case 'd': DeleteRec(current); quit = TRUE; break; case 'e': UnlinkRec(current); EditRec(current); LinkRec(current); quit = TRUE; break; case 'q': quit = TRUE; break; default: printf("\nError\nPlease enter a valid response.\n"); } } else printf("\nError\nPlease enter a valid response.\n"); flag = TRUE; } if(current != FIRST && current != LAST && !flag) { printf("\nP %8s\tN %8s", "Previous", "Next"); printf("\nD %8s\tE %8s", "Delete", "Edit"); printf("\nQ %8s\n", "Quit"); fgets(buff, 255, stdin); buff[0] = tolower(buff[0]); if(buff[1] == '\n') { switch(buff[0]) { case 'p': current = current -> previous; break; case 'n': current = current -> next; break; case 'd': DeleteRec(current); quit = TRUE; break; case 'e': UnlinkRec(current); EditRec(current); LinkRec(current); quit = TRUE; break; case 'q': quit = TRUE; break; default: printf("\nError\nPlease enter a valid response.\n"); } } else printf("\nError\nPlease enter a valid response.\n"); flag = TRUE; } if(current == LAST && current != FIRST && !flag) { printf("\nP %8s", "Previous"); printf("\nD %8s\tE %8s", "Delete", "Edit"); printf("\nQ %8s\n", "Quit"); fgets(buff, 255, stdin); buff[0] = tolower(buff[0]); if(buff[1] == '\n') { switch(buff[0]) { case 'p': current = current -> previous; break; case 'd': DeleteRec(current); quit = TRUE; break; case 'e': UnlinkRec(current); EditRec(current); LinkRec(current); quit = TRUE; break; case 'q': quit = TRUE; break; default: printf("\nError\nPlease enter a valid response.\n"); } } else printf("\nError\nPlease enter a valid response.\n"); flag = TRUE; } } } else printf("\nError\nNo database is open or no records in database.\n"); GetEnter(); return; }
Function to save and close the database.
#include "project.h" void CloseData(void) { if(filename[0]) //If File open { FILE* database; //Declare Variable int i = 0; Header(); printf("\nClose the Database\n"); database = fopen(filename, "wt"); //Open database for writing for(i = 0; i < 256; i++) //Write file if(array[i].number[0] != '\0') { fprintf(database, "%s\n", array[i].number); fprintf(database, "%s\n", array[i].title); fprintf(database, "%d\n", array[i].credit); fprintf(database, "%d\n", array[i].lab); } fclose(database); //Close file FIRST = NULL; //Re-initialize array LAST = NULL; filename[0] = '\0'; for(i = 0; i < 256; i++) InitializeRec(&array[i]); } else printf("\nError\nNo database is open.\n"); //Error if no is open GetEnter(); return; }
Function to delete a record from the doubly linked list and free the memory.
#include "project.h" void DeleteRec(COURSE* record) { Header(); printf("\nDelete a Record\n"); UnlinkRec(record); InitializeRec(record); printf("\nRecord Deleted Sucessfully!\n"); GetEnter(); return; }
Function to print out the contents of a record.
#include "project.h" void DisplayRec(COURSE* record) { printf("\n\nNumber: %s", record -> number); printf("\nTitle: %s", record -> title); printf("\nCredit: %d", record -> credit); printf("\nLab: %d", record -> lab); return; }
Function to read user input and store this in an already existing record.
#include "project.h" void EditRec(COURSE* record) { GetNumber(record); GetTitle(record); GetCredit(record); GetLab(record); return; }
Function to read the credit value.
#include "project.h" void GetCredit(COURSE* record) { int i; //Declare variables char buff[255]; BOOLEAN error; do //Loop if Error { error = FALSE; printf("Please enter the number of credits: "); fgets(buff, 255, stdin); sscanf(buff, "%d", &(record -> credit)); if(record -> credit > 9 || record -> credit < 0) //Sanity Check { printf("\nError\nPlease enter a valid response.\n"); error = TRUE; } }while(error); return; }
Function to prompt for enter to continue.
#include "project.h" void GetEnter(void){ char temp[2]; printf("\nPress [Enter] to continue..."); fgets(temp, 2, stdin); }
Function to prompt for lab.
#include "project.h" void GetLab(COURSE* record) { int i; //Declare Variables char buff[255]; BOOLEAN error; do //Repeat if Error { printf("Is there a lab? (Y/N): "); //Prompt fgets(buff, 255, stdin); error = FALSE; buff[0] = tolower(buff[0]); //lowercase input if((buff[0] == 'y' || buff[0] == 'n') && buff[1] == '\n') //Sanity Check if(buff[0] == 'y') //find lab value record -> lab = 1; else record -> lab = 0; else { printf("\nError\nPlease enter a valid response.\n"); //Error response error = TRUE; } }while(error); return; }
Function to get the user's input on the main menu.
#include "stdio.h" char GetMainMenuChoice(char* prompt) { char (return_value); //Declare variables char buff[256]; printf("\n%s", prompt); //Print Prompt fgets(buff, 255, stdin); return_value = tolower(buff[0]); //lowercase response if(buff[1] != '\n') //return null if more than 1 char inputted return_value = '\0'; return(return_value); }
Function to read in a number from standard input.
#include "project.h" void GetNumber(COURSE* record) { int i; //Declare incrementing variable printf("Please enter the course number: "); fgets(record -> number, 17, stdin); for(i = 0; i < 17; i++) //Change new line to null and upcase string { record -> number[i] = toupper(record -> number[i]); if(record -> number[i] == '\n') record -> number[i] = '\0'; } return; }
Function to get a course number for the database.
#include "project.h" void GetTitle(COURSE* record) { int i; //Declare incrementing variable printf("Please enter the course title: "); //print prompt fgets(record -> title, 65, stdin); //get response for(i = 0; i < 65; i++) //place null at end of string if(record -> number[i] == '\n') record -> number[i] = '\0'; return; }
Function to print a header at the program's startup.
#include "project.h" void Header(void){ //display the header (You can change the name to whatever you'd like Sam...) system("clear"); printf(" _____ _ ______ _ _ _ \n"); printf(" | __ \\ | | | ____| | (_) | \n"); printf(" | | | | __ _| |_ __ _| |__ __| |_| |_ ___ _ __ \n"); printf(" | | | |/ _` | __/ _` | __| / _` | | __/ _ \\| '__|\n"); printf(" | |__| | (_| | || (_| | |___| (_| | | || (_) | | \n"); printf(" |_____/ \\__,_|\\__\\__,_|______\\__,_|_|\\__\\___/|_| \n"); }
Function to give default values of 0 to a course record.
#include "project.h" void InitializeRec(COURSE* CoursePointer) { CoursePointer -> number[0] = 0; CoursePointer -> title [0] = 0; CoursePointer -> credit = 0; CoursePointer -> lab = FALSE; CoursePointer -> next = NULL; CoursePointer -> previous = NULL; return; }
Function to add and link a record to the linked list.
#include "project.h" void LinkRec(COURSE* new) { COURSE* next_rec; //Declare variables COURSE* prev_rec; if(!FIRST) //if no records currently exist { FIRST = new; LAST = new; new->next = NULL; new->previous = NULL; } else { if(strcmp(new->number, FIRST->number) == -1) //case new record will be first { new->previous = NULL; new->next = FIRST; FIRST->previous = new; FIRST = new; } if(strcmp(new->number, LAST->number) == 1) //case new record will be last { new->next = NULL; new->previous = LAST; LAST->next = new; LAST = new; } if(strcmp(new->number, FIRST->number) == 1 && strcmp(new->number, LAST->number) == -1) //case new record is in the middle { next_rec = FIRST; do { next_rec = (next_rec->next); }while(strcmp(next_rec->number, new->number) != 1); prev_rec = (next_rec->previous); (next_rec->previous) = new; (prev_rec->next) = new; new->next = next_rec; new->previous = prev_rec; } } return; }
Function to make a new database file.
#include "project.h" void NewDat(void){ char temp[256] = " "; char buffer[262] = "touch "; int dot; FILE* my_file; BOOLEAN error; int i; int j; int len; do //repeat if error { Header(); printf("\nNew Database\n"); printf("\nPlease input a filename for this new database: "); fgets(temp, 256, stdin); temp[strlen(temp)] = '\0'; error = FALSE; dot = 0; for(i = 0; i < 256; i++) { if(temp[i] == '.') dot = i; if(temp[i] == '\n') temp[i] = '\0'; } if(!dot) { len = strlen(temp); temp[len] = '.'; temp[len + 1] = 'd'; temp[len + 2] = 'a'; temp[len + 3] = 't'; temp[len + 4] = '\0'; } strcat(buffer, temp); printf("%s", buffer); GetEnter(); system(buffer); my_file = fopen(temp, "rt"); //open file if(!my_file) //error if file does not exist { printf("\nError\nThat file does not exist.\n"); error = TRUE; } }while(error); }
Function to open a database file and read in the values.
#include "project.h" void OpenData(void) { if(!filename[0]) //if database not open { char buff[255]; //Declare variables FILE* database; BOOLEAN error; int dot; int i = 0; int j = 0; int len; Header(); printf("\nOpen Database\n"); do //repeat if error { error = FALSE; dot = 0; printf("\nDatabases in folder: \n"); system("dir *.dat"); printf("\nPlease type the name of the file you wish to open\n"); printf("If you do not add an extension the .dat file extention will be added for you.\n"); fgets(filename, 255, stdin); for(i = 0; i < 256; i++) { if(filename[i] == '.') dot = i; if(filename[i] == '\n') filename[i] = '\0'; } if(!dot) { len = strlen(filename); filename[len] = '.'; filename[len + 1] = 'd'; filename[len + 2] = 'a'; filename[len + 3] = 't'; filename[len + 4] = '\0'; } database = fopen(filename, "rt"); //open file if(!database) //error if file does not exist { printf("\nError\nThat file does not exist.\n"); error = TRUE; } }while(error); while(!feof(database)) //place values into array until EOF { buff[0] ='\0'; fgets(buff, 17, database); for(i = 0; i < 17; i++) { array[j].number[i] = buff[i]; if(buff[i] == '\n') array[j].number[i] ='\0'; } fgets(buff, 65, database); for(i = 0; i < 65; i++) { array[j].title[i] = buff[i]; if(buff[i] == '\n') array[j].title[i] = '\0'; } fgets(buff, 3, database); for(i = 0; i < 4; i++) if(buff[i] == '\n') buff[i] = '\0'; sscanf(buff, "%d", &array[j].credit); fgets(buff, 3, database); for(i = 0; i < 4; i++) if(buff[i] == '\n') buff[i] = '\0'; sscanf(buff, "%d", &array[j].lab); j++; } fclose(database); //Close file for(i = 0; i < 256; i++) //Link all elements of array if(array[i].number[0]) LinkRec(&array[i]); } else printf("\nError\nDatabase already open.\n"); //Error if database open GetEnter(); return; }
Function to release memory and close the program.
#include "project.h" BOOLEAN QuitProgram(void) { BOOLEAN return_value; //Declare return value variable BOOLEAN error; char buff[255]; if(!filename[0]) //If database closed quit { printf("\nGood-bye\n"); return_value = TRUE; } else //If database open ask to close { do { error = FALSE; printf("\nA database is open.\nDo you want to save before quitting? (Y/N): "); fgets(buff, 255, stdin); buff[0] = tolower(buff[0]); if((buff[0] != 'y' && buff[0] != 'n') || buff[1] != '\n') { printf("\nError\nPlease enter a valid response\n"); error = TRUE; } else { if(buff[0] == 'y') { CloseData(); return_value = QuitProgram(); } else { filename[0] = '\0'; return_value = QuitProgram(); } } }while(error); } return(return_value); }
Function to read a record from the file.
#include "project.h" void ReadRec(COURSE* CoursePointer) { FILE* record; //Declare variables int i = 0; record = fopen("Record.txt", "rt"); //Open file fgets(CoursePointer -> number, 17, record); //read number for(i = 0; i <= 17; i++) if(CoursePointer -> number[i] == '\n') CoursePointer -> number[i] = '\0'; fgets(CoursePointer -> title, 65, record); //read title for(i = 0; i <= 65; i++) if(CoursePointer -> title[i] == '\n') CoursePointer -> title[i] = '\0'; fscanf(record, "%d", &CoursePointer -> credit); //read credit fscanf(record, "%d", &CoursePointer -> lab); //read lab fclose(record); //close file return; }
Function to copy a record.
#include "project.h" void RecCpy(COURSE* dest, COURSE* source) { strcpy(dest -> number, source -> number); strcpy(dest -> title, source -> title); dest -> credit = source -> credit; dest -> lab = source -> lab; dest -> next = source -> next; dest -> previous = source -> previous; return; }
Unfinished function that would have searched the database for a record.
#include "project.h" void SearchData(void) { printf("\nSearch for a Record\n"); return; }
Function to remove a linked list record from the list.
#include "project.h" void UnlinkRec(COURSE* record) { COURSE* record_prev; //declare variables COURSE* record_next; BOOLEAN flag; record_prev = record -> previous; //intialize variables record_next = record -> next; flag = FALSE; if(record == FIRST && record == LAST && !flag) //case: only record { LAST = NULL; FIRST = NULL; } if(record == FIRST && record != LAST && !flag) //case: multiple records and first record { FIRST = record_next; record_next -> previous = NULL; } if(record != FIRST && record != LAST && !flag) //case: multiple records and not first or last { record_prev -> next = record_next; record_next -> previous = record_prev; } if(record != FIRST && record == LAST && !flag) //case: multiple records and last record { LAST = record_prev; record_prev -> next = NULL; } return; }
Function to save a record to the file.
#include "project.h" void WriteRec(COURSE* CoursePointer) { FILE* record; //Declare file pointer record = fopen("Record.txt", "wt"); //Open file fprintf(record, "%s\n", CoursePointer -> number); fprintf(record, "%s\n", CoursePointer -> title); fprintf(record, "%d\n", CoursePointer -> credit); fprintf(record, "%d\n", CoursePointer -> lab); fclose(record); //Close file return; }
Comments
Post a Comment