Building a File-Based Student Management System in C

System Architecture and User Roles

This project implements a robust student administration system using the C programming language. The system relies on file-based persistence to store data, utilizing text files to maintain records for students, teachers, and academic performance. Access control is managed through three distinct roles: Administrators, Teachers, and Students. The architecture ensures that permissions are strictly enforced; for instance, only Administrators can create new user IDs, while Students are restricted to viewing or modifying their own data.

Authentication Module

Authentication is handled by verifying credentials against the stored database files. The system uses a unique ID as the primary identifier. Before a user can fully register an account, their ID must be pre-allocated by an Administrator to ensure data integrity.

User Registration Logic

The registrasion function validates the existence of the target ID within the master record file. If the ID exists, the user is prompted to set a password. The system employs a temporary file strategy to update records atomically: it reads the original file, writes modified content to a temporary buffer, and then replaces the original file to prevent data corruption during write operations.

void setup_user_account(const char* role_type) {
    UserProfile target_user;
    FILE* data_stream = fopen("student_records.txt", "r");
    if (!data_stream) {
        perror("Unable to access database");
        exit(EXIT_FAILURE);
    }

    FILE* temp_stream = fopen("temp_buffer.dat", "wb");
    if (!temp_stream) {
        fclose(data_stream);
        perror("Unable to create temp file");
        exit(EXIT_FAILURE);
    }

    int target_id;
    printf("Enter your User ID: ");
    scanf("%d", &target_id);

    char buffer[256];
    int is_found = 0;
    
    while (fgets(buffer, sizeof(buffer), data_stream)) {
        int rec_id;
        char class_name[20], full_name[20], gender[10];
        int age;
        char phone_num[20];
        float score_math, score_eng, score_chi;
        char user_name[20], pass_code[20], user_role[20];

        if (sscanf(buffer, "%d %s %s %s %d %s %f %f %f %s %s %s", 
                   &rec_id, class_name, full_name, gender, &age, phone_num, 
                   &score_math, &score_eng, &score_chi, user_name, pass_code, user_role) != EOF) {
            
            if (rec_id == target_id) {
                // Check if already registered (non-default password)
                if (strcmp(pass_code, "0") != 0 && strcmp(role_type, "teacher") != 0) {
                    printf("Enter current password: ");
                    scanf("%s", target_user.password);
                    if (strcmp(target_user.password, pass_code) != 0) {
                        printf("Authentication failed: Incorrect password.\n");
                        fclose(data_stream);
                        fclose(temp_stream);
                        remove("temp_buffer.dat");
                        return;
                    }
                }
                
                is_found = 1;
                printf("Set new password: ");
                scanf("%s", target_user.password);
                
                // Write updated record
                fprintf(temp_stream, "%d %s %s %s %d %s %f %f %f %d %s %s\n", 
                        target_id, class_name, full_name, gender, age, phone_num, 
                        score_math, score_eng, score_chi, target_id, target_user.password, role_type);
                printf("Account setup successful. Role: %s\n", role_type);
            } else {
                // Retain original data
                fputs(buffer, temp_stream);
            }
        }
    }

    if (!is_found) {
        printf("Error: ID %d not found in system records.\n", target_id);
    }

    fclose(data_stream);
    fclose(temp_stream);
    
    // Atomic file update
    remove("student_records.txt");
    rename("temp_buffer.dat", "student_records.txt");
}

Session and Access Control

Once authenticated, the system maintains the current user's context (ID, Role, and Class) in global variables. This allows the aplication to enforce permission checks dynamically throughout the session.

char active_role[20];
char active_class[20];
int active_user_id = -1;

const char* get_active_role() {
    return active_role;
}

const char* get_active_class() {
    return active_class;
}

int get_active_id() {
    return active_user_id;
}

Main Interface and Navigation

The main menu acts as the central dispatcher, routing users to specific functional modules based on their input and role permissions. The Student module is the core of the system, handling CRUD (Create, Read, Update, Delete) operations for student profiles.

Student Profile Management

Administrators have full privileges to add and delete students. Teachers can view student details, while Students can only query or modify thier own personal information. The following example demonstrates the logic for modifying student details, incorporating strict permission checks.

void update_student_profile() {
    FILE* db_file = fopen("student_records.txt", "r");
    FILE* temp_file = fopen("temp_update.dat", "wb");
    
    if (!db_file || !temp_file) {
        perror("File operation failed");
        return;
    }

    int target_id;
    printf("Enter Student ID to modify: ");
    scanf("%d", &target_id);

    // Permission Check
    if (strcmp(get_active_role(), "student") == 0 && get_active_id() != target_id) {
        printf("Access Denied: You can only modify your own profile.\n");
        fclose(db_file);
        fclose(temp_file);
        remove("temp_update.dat");
        return;
    }

    char line[256];
    int found = 0;
    char new_class[20], new_name[20], new_gender[10];
    int new_age;
    char new_phone[20];

    while (fgets(line, sizeof(line), db_file)) {
        int rec_id;
        char class_name[20], full_name[20], gender[10];
        int age;
        char phone_num[20];
        float m, e, c;
        char u_name[20], pwd[20], role[20];

        if (sscanf(line, "%d %s %s %s %d %s %f %f %f %s %s %s", 
                   &rec_id, class_name, full_name, gender, &age, phone_num, 
                   &m, &e, &c, u_name, pwd, role) != EOF) {
            
            if (rec_id == target_id) {
                found = 1;
                printf("Updating record for: %s\n", full_name);
                printf("Enter new Class: "); scanf("%s", new_class);
                printf("Enter new Name: "); scanf("%s", new_name);
                printf("Enter new Gender: "); scanf("%s", new_gender);
                printf("Enter new Age: "); scanf("%d", &new_age);
                printf("Enter new Phone: "); scanf("%s", new_phone);

                fprintf(temp_file, "%d %s %s %s %d %s %f %f %f %s %s %s\n", 
                        rec_id, new_class, new_name, new_gender, new_age, new_phone, 
                        m, e, c, u_name, pwd, role);
                printf("Profile updated successfully.\n");
            } else {
                fputs(line, temp_file);
            }
        }
    }

    fclose(db_file);
    fclose(temp_file);
    remove("student_records.txt");
    rename("temp_update.dat", "student_records.txt");
    
    if (!found) printf("Student ID %d not found.\n", target_id);
}

Academic Performance Management

Grades are managed separately from personal profile data. Teachers and Administrators can input and modify scores, while Students are restricted to read-only access for their own grades. The system also provides analytical tools, such as calculating class-wide averages and generating score rankings.

Score Ranking Logic

To generate rankings, the system loads student records into an in-memory structure, sorts them based on total scores, and outputs the results. The process distinguishes between school-wide rankings and class-specific rankings.

void display_score_rankings() {
    FILE* fp = fopen("student_records.txt", "r");
    if (!fp) {
        perror("Database access error");
        return;
    }

    struct GradeData {
        int id;
        char name[20];
        float total_score;
    } school_list[100], class_list[100];

    int school_count = 0;
    int class_count = 0;
    const char* current_user_class = get_active_class();

    char buffer[256];
    while (fgets(buffer, sizeof(buffer), fp)) {
        int id;
        char cls[20], name[20], gender[10];
        int age;
        char phone[20];
        float math, eng, chi;
        char u[20], p[20], r[20];

        if (sscanf(buffer, "%d %s %s %s %d %s %f %f %f %s %s %s", 
                   &id, cls, name, gender, &age, phone, &math, &eng, &chi, u, p, r) != EOF) {
            
            if (strcmp(r, "student") == 0) {
                float total = math + eng + chi;
                
                // Add to school list
                school_list[school_count].id = id;
                strcpy(school_list[school_count].name, name);
                school_list[school_count].total_score = total;
                school_count++;

                // Add to class list if matches
                if (strcmp(cls, current_user_class) == 0) {
                    class_list[class_count].id = id;
                    strcpy(class_list[class_count].name, name);
                    class_list[class_count].total_score = total;
                    class_count++;
                }
            }
        }
    }
    fclose(fp);

    // Sort School Ranking (Bubble Sort)
    for (int i = 0; i < school_count - 1; i++) {
        for (int j = 0; j < school_count - i - 1; j++) {
            if (school_list[j].total_score < school_list[j+1].total_score) {
                struct GradeData temp = school_list[j];
                school_list[j] = school_list[j+1];
                school_list[j+1] = temp;
            }
        }
    }

    // Sort Class Ranking
    for (int i = 0; i < class_count - 1; i++) {
        for (int j = 0; j < class_count - i - 1; j++) {
            if (class_list[j].total_score < class_list[j+1].total_score) {
                struct GradeData temp = class_list[j];
                class_list[j] = class_list[j+1];
                class_list[j+1] = temp;
            }
        }
    }

    printf("\n--- School-Wide Rankings ---\n");
    printf("Rank\tID\tName\tTotal Score\n");
    for (int i = 0; i < school_count; i++) {
        printf("%d\t%d\t%s\t%.2f\n", i+1, school_list[i].id, school_list[i].name, school_list[i].total_score);
    }

    printf("\n--- Class Rankings ---\n");
    printf("Rank\tID\tName\tTotal Score\n");
    for (int i = 0; i < class_count; i++) {
        printf("%d\t%d\t%s\t%.2f\n", i+1, class_list[i].id, class_list[i].name, class_list[i].total_score);
    }
}

Faculty Management

Teacher data is stored in a separate file (faculty\_data.txt). The management of this resource is restricted to Administrators to prevent unauthorized modifications. Functionalities include adding new faculty profiles, querying teacher details, and updating contact information.

Querying Faculty Information

void search_faculty(const char* name_query) {
    FILE* fp = fopen("faculty_data.txt", "r");
    if (!fp) {
        perror("Faculty file not found");
        return;
    }

    char buffer[128];
    int match_found = 0;
    
    while (fgets(buffer, sizeof(buffer), fp)) {
        char fname[20], fgender[10], fsubj[20], fphone[20], faddr[50];
        int fage;
        
        if (sscanf(buffer, "%s %s %d %s %s %s", fname, fgender, &fage, fsubj, fphone, faddr) == 6) {
            if (strcmp(fname, name_query) == 0) {
                printf("Teacher Found:\n");
                printf("Name: %s\nGender: %s\nAge: %d\nSubject: %s\nPhone: %s\nAddress: %s\n",
                       fname, fgender, fage, fsubj, fphone, faddr);
                match_found = 1;
                break;
            }
        }
    }
    
    if (!match_found) {
        printf("No records found for teacher: %s\n", name_query);
    }
    fclose(fp);
}

Tags: c programming File I/O Data Structures System Design CRUD Operations

Posted on Fri, 29 May 2026 21:00:17 +0000 by poison