Project Progress
0%
Capstone Project  ยท  Structs + Files + Menu-Driven Design

Library Management System

A complete, menu-driven C program that manages a small library โ€” issuing and returning books, automatic overdue fine calculation, search, and saving records to a file.

Book struct & data
Issue & search
Return & fine calc
File saving
Main menu
๐Ÿ“–

Project Overview

Every book in the library is a struct holding its ID, title, author, and issue status. The whole library is just an array of these structs โ€” the rest of the program is functions that read or update that array.

  • Display All Books โ€” prints a formatted table of the full catalog
  • Issue a Book โ€” assigns a book to a member and starts a day counter
  • Return a Book โ€” calculates any overdue fine and frees the book
  • Search Book โ€” looks up a book by its ID
  • Save to File โ€” writes the full catalog to a text file for persistence
Concept usedWhere
structBook record: ID, title, author, status, borrower, days issued
ArraysBook library[TOTAL_BOOKS] holds the entire catalog
FunctionsOne function per menu operation โ€” keeps main() clean
switch-caseRoutes the user's menu choice to the right function
File I/Ofopen/fprintf to persist catalog data
Conditional fine logicOverdue calculation in returnBook()
part 1
1

Book Struct & Catalog Initialization

Data model

Every book is described by one Book struct. The catalog is a fixed-size array โ€” TOTAL_BOOKS makes it easy to resize later. initLibrary() pre-loads 5 books so the program has data to work with immediately, and a due period of 14 days before fines start.

Part 1 ยท library.c โ€” structs & setup
library.c
C
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define TOTAL_BOOKS 5
#define DUE_DAYS 14
#define FINE_PER_DAY 5.0

typedef struct {
    int  id;
    char title[50];
    char author[40];
    int  isIssued;
    char issuedTo[40];
    int  daysIssued;   // how many days it has been out
} Book;

Book library[TOTAL_BOOKS];   // the entire catalog lives in this array

void initLibrary() {
    char *titles[]  = {"The C Programming Language", "Clean Code",
                        "Data Structures Basics", "Algorithms 101", "Operating Systems"};
    char *authors[] = {"K&R", "R. Martin", "A. Verma", "T. Cormen", "A. Silberschatz"};

    for (int i = 0; i < TOTAL_BOOKS; i++) {
        library[i].id = 1001 + i;
        strcpy(library[i].title, titles[i]);
        strcpy(library[i].author, authors[i]);
        library[i].isIssued = 0;
        strcpy(library[i].issuedTo, "-");
        library[i].daysIssued = 0;
    }
}
๐Ÿ’ก Why store daysIssued instead of a real date? Keeping it simple โ€” a full system would use time.h to record actual issue/due dates. Here, the user enters the number of days the book has been out at return time, which is enough to demonstrate the fine logic without extra date-handling complexity.
part 2
2

Display, Search & Issue a Book

Core operations

findBookIndex() is the shared helper โ€” it turns a book *ID* the user types into an array *index*. Both issuing and searching call it before touching any data, exactly like the room lookup in the Hotel project.

Part 2 ยท library.c โ€” display, search, issue
library.c
C
void displayBooks() {
    printf("\n%-6s %-28s %-16s %-10s %-12s\n",
           "ID", "Title", "Author", "Status", "Issued To");
    for (int i = 0; i < TOTAL_BOOKS; i++) {
        printf("%-6d %-28s %-16s %-10s %-12s\n",
               library[i].id, library[i].title, library[i].author,
               library[i].isIssued ? "Issued" : "Available", library[i].issuedTo);
    }
}

int findBookIndex(int id) {
    for (int i = 0; i < TOTAL_BOOKS; i++)
        if (library[i].id == id)
            return i;
    return -1;   // not found
}

void issueBook() {
    int id;
    char name[40];

    printf("Enter book ID to issue: ");
    scanf("%d", &id);

    int idx = findBookIndex(id);
    if (idx == -1) { printf("Book not found.\n"); return; }
    if (library[idx].isIssued) { printf("Book already issued.\n"); return; }

    printf("Enter member name: ");
    scanf(" %[^\n]", name);   // allows full names with spaces

    library[idx].isIssued = 1;
    strcpy(library[idx].issuedTo, name);
    library[idx].daysIssued = 0;

    printf("\"%s\" issued to %s.\n", library[idx].title, name);
}

void searchBook() {
    int id;
    printf("Enter book ID to search: ");
    scanf("%d", &id);

    int idx = findBookIndex(id);
    if (idx == -1) { printf("Book not found.\n"); return; }

    printf("[%d] %s by %s | %s | Issued to: %s\n",
           library[idx].id, library[idx].title, library[idx].author,
           library[idx].isIssued ? "Issued" : "Available", library[idx].issuedTo);
}
โš ๏ธ Always check isIssued before issuing. Without that guard, the same book could be "issued" to two different members at once, silently overwriting the first member's name.
part 3
3

Return with Fine Calculation & File Saving

Overdue logic + persistence

Returning a book asks how many days it was actually kept, compares that against the DUE_DAYS limit, and only charges a fine for the days over the limit. saveToFile() writes the whole catalog as CSV lines, just like the Hotel project's room export.

Part 3 ยท library.c โ€” return & file I/O
library.c
C
void returnBook() {
    int id, daysKept;
    printf("Enter book ID to return: ");
    scanf("%d", &id);

    int idx = findBookIndex(id);
    if (idx == -1) { printf("Book not found.\n"); return; }
    if (!library[idx].isIssued) { printf("This book was not issued.\n"); return; }

    printf("Enter number of days kept: ");
    scanf("%d", &daysKept);

    printf("\n----- Return Receipt -----\n");
    printf("Book  : %s\n", library[idx].title);
    printf("Member: %s\n", library[idx].issuedTo);
    printf("Days kept: %d (allowed: %d)\n", daysKept, DUE_DAYS);

    if (daysKept > DUE_DAYS) {
        int overdueDays = daysKept - DUE_DAYS;
        float fine = overdueDays * FINE_PER_DAY;
        printf("Overdue by %d day(s) -> Fine: Rs %.2f\n", overdueDays, fine);
    } else {
        printf("Returned on time. No fine.\n");
    }

    // free the book for the next member
    library[idx].isIssued = 0;
    strcpy(library[idx].issuedTo, "-");
    library[idx].daysIssued = 0;
}

void saveToFile() {
    FILE *fp = fopen("library_data.txt", "w");
    if (!fp) { printf("Error saving file.\n"); return; }

    for (int i = 0; i < TOTAL_BOOKS; i++) {
        fprintf(fp, "%d,%s,%s,%d,%s\n",
                library[i].id, library[i].title, library[i].author,
                library[i].isIssued, library[i].issuedTo);
    }
    fclose(fp);
    printf("Data saved to library_data.txt\n");
}
๐Ÿ’ก The fine formula in one line: fine = max(0, daysKept - DUE_DAYS) * FINE_PER_DAY. The if check does the "max(0, ...)" part manually โ€” no fine is ever charged for returning on time or early.
part 4
4

The Main Menu

do-while + switch

Same pattern as every project in this series: main() stays small, looping with a do-while and routing choices with switch. Keeping main() thin makes the whole program easier to read and extend.

Part 4 ยท library.c โ€” main()
library.c
C
int main() {
    initLibrary();
    int choice;

    do {
        printf("\n===== LIBRARY MANAGEMENT SYSTEM =====\n");
        printf("1. Display All Books\n");
        printf("2. Issue a Book\n");
        printf("3. Return a Book\n");
        printf("4. Search Book\n");
        printf("5. Save Data to File\n");
        printf("6. Exit\n");
        printf("Enter choice: ");
        scanf("%d", &choice);

        switch (choice) {
            case 1: displayBooks(); break;
            case 2: issueBook();    break;
            case 3: returnBook();   break;
            case 4: searchBook();   break;
            case 5: saveToFile();   break;
            case 6: printf("Exiting... Goodbye!\n"); break;
            default: printf("Invalid choice.\n");
        }
    } while (choice != 6);

    return 0;
}
terminal โ€” sample session
output
===== LIBRARY MANAGEMENT SYSTEM =====
1. Display All Books
2. Issue a Book
3. Return a Book
4. Search Book
5. Save Data to File
6. Exit
Enter choice: 1

ID     Title                        Author           Status     Issued To
1001   The C Programming Language  K&R              Available  -
1002   Clean Code                  R. Martin        Available  -
1003   Data Structures Basics      A. Verma         Available  -
1004   Algorithms 101               T. Cormen        Available  -
1005   Operating Systems           A. Silberschatz  Available  -

Enter choice: 2
Enter book ID to issue: 1003
Enter member name: Ananya Rao
"Data Structures Basics" issued to Ananya Rao.

Enter choice: 3
Enter book ID to return: 1003
Enter number of days kept: 20

----- Return Receipt -----
Book  : Data Structures Basics
Member: Ananya Rao
Days kept: 20 (allowed: 14)
Overdue by 6 day(s) -> Fine: Rs 30.00

Enter choice: 6
Exiting... Goodbye!
extend it
๏ผ‹

Ways to Extend This Project

Once the base version compiles and runs, these upgrades each reuse a concept you've already covered in earlier lessons:

  • Load from file on startup โ€” read library_data.txt with fscanf so the catalog survives between runs
  • Dynamic catalog size โ€” replace the fixed array with malloc-allocated memory sized from user input
  • Waitlist per book โ€” a linked list of members waiting for a currently-issued book
  • Search by title โ€” linear search with strstr for partial title matches
  • Sort catalog by title or author โ€” plug in any algorithm from the Sorting lesson
  • Real due dates โ€” use time.h to store actual issue/due dates instead of a manually entered day count
ExtensionConcept it reuses
Persistent load/saveFile I/O lesson
Dynamic catalogDynamic memory (malloc/realloc) lesson
Waitlist per bookLinked Lists lesson
Sort by title/authorSorting Algorithms lesson
โœ“

Project Checklist

  • I understand the Book struct and what each field stores
  • I can explain how findBookIndex() connects book ID to array index
  • I can trace issueBook() end to end
  • I understand the overdue fine calculation in returnBook()
  • I know why the book is reset after return
  • I understand how saveToFile() writes each book as a CSV line
  • I can trace the do-while + switch main menu loop
  • I compiled and ran the full program myself
  • I picked at least one extension to try next