Contact Book Implementation Using Singly Linked Lists and File I/O in C
Project File Structure (VS2022)
ContactBook.handContactBook.c: Header and implemantation files for core contact book logicLinkedList.handLinkedList.c: Header and implementation files for the singly linked list data structuerapp.c: Test application to interact with the contact book via a menu interfacecontacts.dat: Binary file for persistent storage of contact information
Singly Linked List Implementation
Header File (LinkedList.h)
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "ContactBook.h"
typedef PersonDetails ListData;
typedef struct LinkedListNode {
ListData data;
struct LinkedListNode* next;
} LinkedListNode;
// Append node to the end of the list
void ListAppend(LinkedListNode** head, ListData value);
// Remove node from the start of the list
void ListRemoveHead(LinkedListNode** head);
// Delete a specific node from the list
void ListDeleteNode(LinkedListNode** head, LinkedListNode* target);
// Allocate and initialize a new list node
LinkedListNode* CreateListNode(ListData value);
Source File (LinkedList.c)
#define _CRT_SECURE_NO_WARNINGS
#include "LinkedList.h"
LinkedListNode* CreateListNode(ListData value) {
LinkedListNode* newNode = (LinkedListNode*)malloc(sizeof(LinkedListNode));
if (!newNode) {
perror("Failed to allocate memory for node");
exit(EXIT_FAILURE);
}
newNode->data = value;
newNode->next = NULL;
return newNode;
}
void ListAppend(LinkedListNode** head, ListData value) {
assert(head != NULL);
LinkedListNode* newNode = CreateListNode(value);
if (*head == NULL) {
*head = newNode;
return;
}
LinkedListNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
void ListRemoveHead(LinkedListNode** head) {
assert(head != NULL && *head != NULL);
LinkedListNode* temp = *head;
*head = (*head)->next;
free(temp);
}
void ListDeleteNode(LinkedListNode** head, LinkedListNode* target) {
assert(head != NULL && *head != NULL);
assert(target != NULL);
if (target == *head) {
ListRemoveHead(head);
return;
}
LinkedListNode* prev = *head;
while (prev->next != target) {
prev = prev->next;
}
prev->next = target->next;
free(target);
}
Contact Book Core Logic
Header File (ContactBook.h)
#pragma once
#define NAME_LENGTH 100
#define GENDER_LENGTH 10
#define PHONE_LENGTH 15
#define ADDRESS_LENGTH 200
typedef struct LinkedListNode ContactList;
typedef struct PersonDetails {
char name[NAME_LENGTH];
char gender[GENDER_LENGTH];
int age;
char phone[PHONE_LENGTH];
char address[ADDRESS_LENGTH];
} PersonDetails;
// Initialize contact book from persistent storage
void InitializeContact(ContactList** contactList);
// Add a new contact entry
void AddPerson(ContactList** contactList);
// Remove an existing contact
void RemovePerson(ContactList** contactList);
// Display all stored contacts
void DisplayContacts(ContactList* contactList);
// Search for a contact by name
void SearchContact(ContactList* contactList);
// Update details of an existing contact
void UpdatePerson(ContactList** contactList);
// Cleanup memory and save contacts to file
void DestroyContactList(ContactList** contactList);
Source File (ContactBook.c)
#define _CRT_SECURE_NO_WARNINGS
#include "ContactBook.h"
#include "LinkedList.h"
static LinkedListNode* FindPersonByName(ContactList* contactList, const char* name) {
assert(contactList != NULL);
LinkedListNode* current = contactList;
while (current != NULL) {
if (strcmp(current->data.name, name) == 0) {
return current;
}
current = current->next;
}
return NULL;
}
void InitializeContact(ContactList** contactList) {
*contactList = NULL;
FILE* file = fopen("contacts.dat", "rb");
if (file == NULL) {
perror("Failed to open contacts file");
exit(EXIT_FAILURE);
}
PersonDetails temp;
LinkedListNode* lastNode = NULL;
while (fread(&temp, sizeof(PersonDetails), 1, file) == 1) {
if (*contactList == NULL) {
*contactList = CreateListNode(temp);
lastNode = *contactList;
} else {
lastNode->next = CreateListNode(temp);
lastNode = lastNode->next;
}
}
fclose(file);
}
void AddPerson(ContactList** contactList) {
PersonDetails newPerson = {0};
printf("Enter name: ");
scanf("%s", newPerson.name);
printf("Enter gender: ");
scanf("%s", newPerson.gender);
printf("Enter age: ");
scanf("%d", &newPerson.age);
printf("Enter phone number: ");
scanf("%s", newPerson.phone);
printf("Enter address: ");
scanf("%s", newPerson.address);
ListAppend(contactList, newPerson);
printf("Contact added successfully!\n");
}
void RemovePerson(ContactList** contactList) {
assert(*contactList != NULL);
char targetName[NAME_LENGTH];
printf("Enter the name of the contact to remove: ");
scanf("%s", targetName);
LinkedListNode* found = FindPersonByName(*contactList, targetName);
if (found == NULL) {
printf("Contact not found!\n");
return;
}
ListDeleteNode(contactList, found);
printf("Contact removed successfully!\n");
}
void DisplayContacts(ContactList* contactList) {
if (contactList == NULL) {
printf("No contacts stored.\n");
return;
}
printf("%-15s\t%-10s\t%-5s\t%-20s\t%-30s\n", "Name", "Gender", "Age", "Phone", "Address");
LinkedListNode* current = contactList;
while (current != NULL) {
printf("%-15s\t%-10s\t%-5d\t%-20s\t%-30s\n",
current->data.name,
current->data.gender,
current->data.age,
current->data.phone,
current->data.address);
current = current->next;
}
}
void SearchContact(ContactList* contactList) {
assert(contactList != NULL);
char targetName[NAME_LENGTH];
printf("Enter the name of the contact to search: ");
scanf("%s", targetName);
LinkedListNode* found = FindPersonByName(contactList, targetName);
if (found == NULL) {
printf("Contact not found!\n");
return;
}
printf("%-15s\t%-10s\t%-5s\t%-20s\t%-30s\n", "Name", "Gender", "Age", "Phone", "Address");
printf("%-15s\t%-10s\t%-5d\t%-20s\t%-30s\n",
found->data.name,
found->data.gender,
found->data.age,
found->data.phone,
found->data.address);
}
void UpdatePerson(ContactList** contactList) {
assert(*contactList != NULL);
char targetName[NAME_LENGTH];
printf("Enter the name of the contact to update: ");
scanf("%s", targetName);
LinkedListNode* found = FindPersonByName(*contactList, targetName);
if (found == NULL) {
printf("Contact not found!\n");
return;
}
printf("Enter new name: ");
scanf("%s", found->data.name);
printf("Enter new gender: ");
scanf("%s", found->data.gender);
printf("Enter new age: ");
scanf("%d", &found->data.age);
printf("Enter new phone number: ");
scanf("%s", found->data.phone);
printf("Enter new address: ");
scanf("%s", found->data.address);
printf("Contact updated successfully!\n");
}
void DestroyContactList(ContactList** contactList) {
FILE* file = fopen("contacts.dat", "wb");
if (file == NULL) {
perror("Failed to save contacts");
exit(EXIT_FAILURE);
}
LinkedListNode* current = *contactList;
while (current != NULL) {
fwrite(¤t->data, sizeof(PersonDetails), 1, file);
LinkedListNode* temp = current;
current = current->next;
free(temp);
}
*contactList = NULL;
fclose(file);
}
User Interface Application (app.c)
#define _CRT_SECURE_NO_WARNINGS
#include "ContactBook.h"
#include "LinkedList.h"
typedef enum {
QUIT = 0,
ADD_ENTRY,
REMOVE_ENTRY,
SEARCH_ENTRY,
UPDATE_ENTRY,
VIEW_ALL
} MenuOption;
static void PrintMenu() {
printf("=========== Contact Book ===========\n");
printf("1. Add New Contact\n");
printf("2. Remove Contact\n");
printf("3. Search Contact\n");
printf("4. Update Contact\n");
printf("5. View All Contacts\n");
printf("0. Exit\n");
printf("====================================\n");
}
int main() {
ContactList* contactBook = NULL;
InitializeContact(&contactBook);
int choice = 0;
do {
PrintMenu();
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case QUIT:
DestroyContactList(&contactBook);
printf("Exiting... Contacts saved.\n");
break;
case ADD_ENTRY:
AddPerson(&contactBook);
break;
case REMOVE_ENTRY:
RemovePerson(&contactBook);
break;
case SEARCH_ENTRY:
SearchContact(contactBook);
break;
case UPDATE_ENTRY:
UpdatePerson(&contactBook);
break;
case VIEW_ALL:
DisplayContacts(contactBook);
break;
default:
printf("Invalid choice! Please try again.\n");
break;
}
system("pause");
fflush(stdin);
system("cls");
} while (choice != QUIT);
return 0;
}
The lines system("pause"); fflush(stdin); system("cls"); serve three key purposes:
system("pause"): Pauses execution to let users review operation resultsfflush(stdin): Clears residual input buffer data to prevent unexpected behavior in subsequent input operationssystem("cls"): Clears the console screen to maintain a clean interface for the next interaction