Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Contact Book Implementation Using Singly Linked Lists and File I/O in C

Tech May 12 4

Project File Structure (VS2022)

  • ContactBook.h and ContactBook.c: Header and implemantation files for core contact book logic
  • LinkedList.h and LinkedList.c: Header and implementation files for the singly linked list data structuer
  • app.c: Test application to interact with the contact book via a menu interface
  • contacts.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(&current->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:

  1. system("pause"): Pauses execution to let users review operation results
  2. fflush(stdin): Clears residual input buffer data to prevent unexpected behavior in subsequent input operations
  3. system("cls"): Clears the console screen to maintain a clean interface for the next interaction

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.