Complete file handling project examples in C — student record management system, phone book application with add/search/delete/display operations, menu-driven programs with binary files.
The best way to master file handling is by building real projects. These two mini-projects combine everything you've learned — structs, file I/O, binary files, and menu-driven programs — into practical applications.
Project 1: Student Record Management System
This system supports adding, displaying, searching, updating, and deleting student records using binary files.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FILENAME "students.dat"
struct Student {
int roll;
char name[50];
float marks[5];
float percentage;
char grade;
};
void calculate_result(struct Student *s) {
float total = 0;
for (int i = 0; i < 5; i++) total += s->marks[i];
s->percentage = total / 5.0;
if (s->percentage >= 90) s->grade = 'A';
else if (s->percentage >= 75) s->grade = 'B';
else if (s->percentage >= 60) s->grade = 'C';
else if (s->percentage >= 40) s->grade = 'D';
else s->grade = 'F';
}
void add_student() {
FILE *fp = fopen(FILENAME, "ab");
if (fp == NULL) {
printf("Error opening file!\n");
return;
}
struct Student s;
printf("\n--- Add New Student ---\n");
printf("Enter Roll Number: ");
scanf("%d", &s.roll);
printf("Enter Name: ");
scanf(" %[^\n]", s.name);
printf("Enter marks for 5 subjects:\n");
for (int i = 0; i < 5; i++) {
printf(" Subject %d: ", i + 1);
scanf("%f", &s.marks[i]);
}
calculate_result(&s);
fwrite(&s, sizeof(struct Student), 1, fp);
fclose(fp);
printf("Student added! (Grade: %c, Percentage: %.1f%%)\n",
s.grade, s.percentage);
}
void display_all() {
FILE *fp = fopen(FILENAME, "rb");
if (fp == NULL) {
printf("No records found.\n");
return;
}
struct Student s;
int count = 0;
printf("\n╔══════╦══════════════════╦════════════╦═══════╗\n");
printf("║ Roll ║ Name ║ Percentage ║ Grade ║\n");
printf("╠══════╬══════════════════╬════════════╬═══════╣\n");
while (fread(&s, sizeof(struct Student), 1, fp) == 1) {
printf("║ %4d ║ %-16s ║ %5.1f%% ║ %c ║\n",
s.roll, s.name, s.percentage, s.grade);
count++;
}
printf("╚══════╩══════════════════╩════════════╩═══════╝\n");
printf("Total records: %d\n", count);
fclose(fp);
}
void search_student() {
FILE *fp = fopen(FILENAME, "rb");
if (fp == NULL) {
printf("No records found.\n");
return;
}
int roll;
printf("\nEnter Roll Number to search: ");
scanf("%d", &roll);
struct Student s;
int found = 0;
while (fread(&s, sizeof(struct Student), 1, fp) == 1) {
if (s.roll == roll) {
printf("\n--- Student Found ---\n");
printf("Roll: %d\n", s.roll);
printf("Name: %s\n", s.name);
printf("Marks: ");
for (int i = 0; i < 5; i++) printf("%.1f ", s.marks[i]);
printf("\nPercentage: %.1f%%\n", s.percentage);
printf("Grade: %c\n", s.grade);
found = 1;
break;
}
}
if (!found) printf("Student with Roll %d not found.\n", roll);
fclose(fp);
}
void delete_student() {
int roll;
printf("\nEnter Roll Number to delete: ");
scanf("%d", &roll);
FILE *fp = fopen(FILENAME, "rb");
FILE *temp = fopen("temp.dat", "wb");
if (fp == NULL || temp == NULL) {
printf("Error!\n");
return;
}
struct Student s;
int deleted = 0;
while (fread(&s, sizeof(struct Student), 1, fp) == 1) {
if (s.roll == roll) {
deleted = 1;
} else {
fwrite(&s, sizeof(struct Student), 1, temp);
}
}
fclose(fp);
fclose(temp);
remove(FILENAME);
rename("temp.dat", FILENAME);
printf(deleted ? "Student deleted.\n" : "Student not found.\n");
}
int main() {
int choice;
while (1) {
printf("\n============================\n");
printf(" STUDENT MANAGEMENT SYSTEM\n");
printf("============================\n");
printf("1. Add Student\n");
printf("2. Display All\n");
printf("3. Search Student\n");
printf("4. Delete Student\n");
printf("5. Exit\n");
printf("Choice: ");
scanf("%d", &choice);
switch (choice) {
case 1: add_student(); break;
case 2: display_all(); break;
case 3: search_student(); break;
case 4: delete_student(); break;
case 5: printf("Goodbye!\n"); return 0;
default: printf("Invalid choice!\n");
}
}
}
============================
STUDENT MANAGEMENT SYSTEM
============================
1. Add Student
2. Display All
3. Search Student
4. Delete Student
5. Exit
Choice: 2
╔══════╦══════════════════╦════════════╦═══════╗
║ Roll ║ Name ║ Percentage ║ Grade ║
╠══════╬══════════════════╬════════════╬═══════╣
║ 101 ║ Alice Johnson ║ 92.6% ║ A ║
║ 102 ║ Bob Smith ║ 80.0% ║ B ║
║ 103 ║ Charlie Brown ║ 67.4% ║ C ║
╚══════╩══════════════════╩════════════╩═══════╝
Total records: 3
Project 2: Phone Book Application
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PHONEBOOK "phonebook.dat"
#define MAX_NAME 50
#define MAX_PHONE 15
#define MAX_EMAIL 50
struct Contact {
int id;
char name[MAX_NAME];
char phone[MAX_PHONE];
char email[MAX_EMAIL];
};
int get_next_id() {
FILE *fp = fopen(PHONEBOOK, "rb");
if (fp == NULL) return 1;
struct Contact c;
int max_id = 0;
while (fread(&c, sizeof(struct Contact), 1, fp) == 1) {
if (c.id > max_id) max_id = c.id;
}
fclose(fp);
return max_id + 1;
}
void add_contact() {
struct Contact c;
c.id = get_next_id();
printf("\n--- Add Contact ---\n");
printf("Name: ");
scanf(" %[^\n]", c.name);
printf("Phone: ");
scanf(" %[^\n]", c.phone);
printf("Email: ");
scanf(" %[^\n]", c.email);
FILE *fp = fopen(PHONEBOOK, "ab");
if (fp == NULL) return;
fwrite(&c, sizeof(struct Contact), 1, fp);
fclose(fp);
printf("Contact added with ID: %d\n", c.id);
}
void search_by_name() {
char query[MAX_NAME];
printf("\nSearch name: ");
scanf(" %[^\n]", query);
FILE *fp = fopen(PHONEBOOK, "rb");
if (fp == NULL) {
printf("No contacts found.\n");
return;
}
struct Contact c;
int found = 0;
while (fread(&c, sizeof(struct Contact), 1, fp) == 1) {
// Case-insensitive partial match
if (strstr(c.name, query) != NULL) {
printf(" [%d] %s | %s | %s\n", c.id, c.name, c.phone, c.email);
found++;
}
}
printf("%d result(s) found.\n", found);
fclose(fp);
}
void display_all_contacts() {
FILE *fp = fopen(PHONEBOOK, "rb");
if (fp == NULL) {
printf("Phone book is empty.\n");
return;
}
struct Contact c;
int count = 0;
printf("\n%-4s %-20s %-15s %s\n", "ID", "Name", "Phone", "Email");
printf("────────────────────────────────────────────────────────\n");
while (fread(&c, sizeof(struct Contact), 1, fp) == 1) {
printf("%-4d %-20s %-15s %s\n", c.id, c.name, c.phone, c.email);
count++;
}
printf("\nTotal contacts: %d\n", count);
fclose(fp);
}
void delete_contact() {
int id;
printf("\nEnter ID to delete: ");
scanf("%d", &id);
FILE *fp = fopen(PHONEBOOK, "rb");
FILE *temp = fopen("temp_pb.dat", "wb");
if (fp == NULL || temp == NULL) return;
struct Contact c;
int deleted = 0;
while (fread(&c, sizeof(struct Contact), 1, fp) == 1) {
if (c.id == id) {
printf("Deleting: %s (%s)\n", c.name, c.phone);
deleted = 1;
} else {
fwrite(&c, sizeof(struct Contact), 1, temp);
}
}
fclose(fp);
fclose(temp);
remove(PHONEBOOK);
rename("temp_pb.dat", PHONEBOOK);
printf(deleted ? "Contact deleted.\n" : "ID not found.\n");
}
int main() {
int choice;
while (1) {
printf("\n╔═══════════════════════╗\n");
printf("║ PHONE BOOK v1.0 ║\n");
printf("╠═══════════════════════╣\n");
printf("║ 1. Add Contact ║\n");
printf("║ 2. Search by Name ║\n");
printf("║ 3. Display All ║\n");
printf("║ 4. Delete Contact ║\n");
printf("║ 5. Exit ║\n");
printf("╚═══════════════════════╝\n");
printf("Choice: ");
scanf("%d", &choice);
switch (choice) {
case 1: add_contact(); break;
case 2: search_by_name(); break;
case 3: display_all_contacts(); break;
case 4: delete_contact(); break;
case 5: printf("Goodbye!\n"); return 0;
default: printf("Invalid!\n");
}
}
}
╔═══════════════════════╗
║ PHONE BOOK v1.0 ║
╠═══════════════════════╣
║ 1. Add Contact ║
║ 2. Search by Name ║
║ 3. Display All ║
║ 4. Delete Contact ║
║ 5. Exit ║
╚═══════════════════════╝
Choice: 3
ID Name Phone Email
────────────────────────────────────────────────────────
1 John Doe 555-1234 john@email.com
2 Jane Smith 555-5678 jane@email.com
3 Bob Wilson 555-9999 bob@company.com
Total contacts: 3
Key Concepts Used in These Projects
| Concept | Where Used |
|---|
| Binary file I/O | All read/write operations |
| fseek() | Random access, updates |
| Struct serialization | Storing records to disk |
| Menu-driven logic | User interaction loop |
| File deletion pattern | Copy-to-temp, rename |
| Error handling | NULL checks on fopen |
Extension Ideas
- Add sorting — Sort contacts by name before display
- Export to CSV — Add option to export data as text
- Login system — Password-protect access to records
- Backup/restore — Copy .dat file for safety
- Pagination — Display records 10 at a time for large datasets
Interview Questions
Q1: Why use binary files instead of text files for these projects?
Binary files enable fixed-size records, making random access possible (jump to record N with fseek). Struct serialization is a single fwrite call instead of parsing multiple fields. Updates are in-place without rewriting the entire file.
Q2: How would you handle concurrent access to the file?
Use file locking (flock() on Linux, LockFile() on Windows) to prevent simultaneous writes. For reads, either allow multiple readers or use a single-reader lock. Alternatively, use a database like SQLite for concurrent access.
Q3: What's the limitation of the copy-to-temp deletion method?
It requires copying the entire file for each deletion — O(n) time and requires 2x disk space temporarily. For large files, use a "mark as deleted" flag and periodically compact the file.
Summary
- File-based CRUD (Create, Read, Update, Delete) operations form the backbone of persistent applications
- Binary files with structs enable database-like functionality
- Menu-driven programs use switch statements in an infinite loop
- Always validate input and check file operation return values
- The copy-to-temp pattern handles deletion safely
- These projects combine structs, pointers, file I/O, and control flow