Building a Small Address Book in C
Mini Project: Address Book System

Requirements: Store contact information:
Name, Gender, Phone
Maximum capacity: 50 contacts
Functional requirements:
- Add a contact
- Delete a contact by name
- Modify a contact by name
- Search contacts by name or phone (supports fuzzy search)
- Display all contacts
- Exit the system
This address book stores data in a file, so even after closing the program, the information persists for the next session.
Without further ado, here is the code.
main.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "contact.h"
#include "utils.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAX_INPUT_LENGTH 100
main.c
Contains the main menu code.
#include "main.h"
int main() {
Contact phonebook[MAX_CONTACTS];
initialize_contacts(phonebook);
int count = 0;
// Load contacts from file into array
load_contacts(phonebook, &count);
int choice;
char input[MAX_INPUT_LENGTH];
do {
printf("\n===== Contact Management System =====\n");
printf("1. Add Contact\n");
printf("2. Delete Contact\n");
printf("3. Modify Contact\n");
printf("4. Search Contact\n");
printf("5. Display All Contacts\n");
printf("6. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1: {
system("clear"); // Use "cls" on Windows
load_contacts(phonebook, &count);
Contact new_entry;
printf("Enter name: ");
scanf("%s", new_entry.name);
printf("Enter gender (M/F): ");
scanf(" %s", new_entry.gender);
printf("Enter phone number: ");
scanf("%s", new_entry.phone);
if (is_valid_name(new_entry.name) && is_valid_phone(new_entry.phone)) {
if (add_contact(phonebook, &count, &new_entry)) {
save_contacts(phonebook, count);
printf("Contact added successfully.\n");
} else {
printf("Failed to add contact.\n");
}
} else {
printf("Invalid name or phone number.\n");
}
break;
}
case 2: {
system("clear");
load_contacts(phonebook, &count);
char target_name[MAX_NAME_LENGTH];
printf("Enter the name of the contact to delete: ");
scanf("%s", target_name);
if (delete_contact(phonebook, &count, target_name)) {
save_contacts(phonebook, count);
printf("Contact deleted successfully.\n");
}
break;
}
case 3: {
system("clear");
char target_name[MAX_NAME_LENGTH];
Contact updated_info;
load_contacts(phonebook, &count);
printf("Enter the name of the contact to modify: ");
scanf("%s", target_name);
printf("Enter new name: ");
scanf("%s", updated_info.name);
printf("Enter new gender (M/F): ");
scanf(" %s", updated_info.gender);
printf("Enter new phone number: ");
scanf("%s", updated_info.phone);
if (is_valid_name(updated_info.name) && is_valid_phone(updated_info.phone)) {
if (modify_contact(phonebook, count, target_name, &updated_info)) {
save_contacts(phonebook, count);
printf("Contact modified successfully.\n");
}
} else {
printf("Invalid name or phone number.\n");
}
break;
}
case 4: {
system("clear");
load_contacts(phonebook, &count);
char query[MAX_INPUT_LENGTH];
printf("Enter search keyword: ");
scanf("%s", query);
search_contact(phonebook, count, query);
break;
}
case 5:
system("clear");
load_contacts(phonebook, &count);
display_contacts(phonebook, count);
break;
case 6:
printf("Exiting program...\n");
exit(0);
default:
printf("Invalid choice, please try again!\n");
}
} while (choice != 6);
return 0;
}
contact.h
#ifndef CONTACT_H
#define CONTACT_H
#define MAX_CONTACTS 50
#define MAX_NAME_LENGTH 50
#define MAX_PHONE_LENGTH 20
typedef struct {
char name[MAX_NAME_LENGTH];
char gender[10];
char phone[MAX_PHONE_LENGTH];
} Contact;
void initialize_contacts(Contact contacts[]);
int add_contact(Contact contacts[], int* num_contacts, const Contact* new_contact);
int delete_contact(Contact contacts[], int* num_contacts, const char* name);
int modify_contact(Contact contacts[], int num_contacts, const char* name, const Contact* new_contact);
void search_contact(Contact contacts[], int num_contacts, const char* query);
void display_contacts(Contact contacts[], int num_contacts);
int load_contacts(Contact contacts[], int* num_contacts);
void save_contacts(Contact contacts[], int num_contacts);
#endif /* CONTACT_H */
contact.c
Contains CRUD functions.
#include "main.h"
void initialize_contacts(Contact list[]) {
for (int i = 0; i < MAX_CONTACTS; ++i) {
list[i].name[0] = '\0';
}
}
int add_contact(Contact list[], int* count, const Contact* new_entry) {
if (*count >= MAX_CONTACTS) {
printf("Address book is full. Cannot add contact.\n");
return 0;
}
list[*count] = *new_entry;
(*count)++;
save_contacts(list, *count);
printf("Contact %s added successfully.\n", new_entry->name);
return 1;
}
int delete_contact(Contact list[], int* count, const char* name) {
int found = 0;
FILE* fp = fopen("contacts.txt", "w");
if (fp == NULL) {
perror("Failed to open contacts.txt");
return 0;
}
for (int i = 0; i < *count; ++i) {
if (strcmp(list[i].name, name) == 0) {
found = 1;
} else {
fprintf(fp, "%s %s %s\n", list[i].name, list[i].gender, list[i].phone);
}
}
fclose(fp);
if (found) {
(*count)--;
printf("Contact %s deleted successfully.\n", name);
return 1;
} else {
printf("Contact with name %s not found.\n", name);
return 0;
}
}
int modify_contact(Contact list[], int count, const char* name, const Contact* updated) {
int found = 0;
for (int i = 0; i < count; ++i) {
if (strcmp(list[i].name, name) == 0) {
list[i] = *updated;
found = 1;
printf("Contact %s updated successfully.\n", name);
break;
}
}
if (!found) {
printf("Contact with name %s not found.\n", name);
} else {
save_contacts(list, count);
}
return found;
}
void display_contacts(Contact list[], int count) {
printf("All contacts:\n");
for (int i = 0; i < count; i++) {
printf("Name: %s Gender: %s Phone: %s\n", list[i].name, list[i].gender, list[i].phone);
}
}
void search_contact(Contact list[], int count, const char* query) {
int found = 0;
printf("Search results:\n");
printf("%-6s %-10s %-10s\n", "Name", "Gender", "Phone");
for (int i = 0; i < count; i++) {
if (strstr(list[i].name, query) != NULL || strstr(list[i].phone, query) != NULL) {
printf("%-6s %-10s %-10s\n", list[i].name, list[i].gender, list[i].phone);
found = 1;
}
}
if (!found) {
printf("No contacts found matching '%s'.\n", query);
}
}
int load_contacts(Contact list[], int* count) {
FILE* fp = fopen("contacts.txt", "r");
if (fp == NULL) {
perror("Failed to open contacts.txt");
return 0;
}
*count = 0;
char line[100];
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%s %s %s", list[*count].name, list[*count].gender, list[*count].phone) == 3) {
(*count)++;
}
}
fclose(fp);
return *count;
}
void save_contacts(Contact list[], int count) {
FILE* fp = fopen("contacts.txt", "w");
if (fp == NULL) {
perror("Failed to open contacts.txt");
return;
}
for (int i = 0; i < count; ++i) {
fprintf(fp, "%s %s %s\n", list[i].name, list[i].gender, list[i].phone);
}
fclose(fp);
}
utils.h
#ifndef UTILS_H
#define UTILS_H
int is_valid_name(const char *name);
int is_valid_phone(const char *phone);
int string_starts_with(const char *str, const char *prefix);
void load_num_contacts(int* num_contacts);
#endif /* UTILS_H */
utils.c
Contains utility functoins for validation and file operations.
#include "main.h"
int is_valid_name(const char* name) {
if (name == NULL || strlen(name) == 0) {
return 0;
}
return 1;
}
int is_valid_phone(const char* phone) {
if (phone == NULL || strlen(phone) == 0) {
return 0;
}
for (int i = 0; phone[i] != '\0'; i++) {
if (!isdigit(phone[i])) {
return 0;
}
}
return 1;
}
int string_starts_with(const char* str, const char* prefix) {
if (str == NULL || prefix == NULL) {
return 0;
}
size_t len_str = strlen(str);
size_t len_prefix = strlen(prefix);
if (len_str < len_prefix) {
return 0;
}
return strncmp(str, prefix, len_prefix) == 0;
}
void load_num_contacts(int* num_contacts) {
FILE* fp = fopen("num_contacts.txt", "r");
if (fp == NULL) {
perror("Failed to open num_contacts.txt");
return;
}
fscanf(fp, "%d", num_contacts);
fclose(fp);
}