Files as databases: writing and reading files

Below is a simple C program that uses an array of structs to input details about students and then writes the structures to a file as a database. The program assumes that each student has a name, roll number, and marks.

Certainly! If you want to write each student structure individually in a loop, you can modify the writeToFile function as follows:

#include <stdio.h>

// Define the structure for a student
struct Student {
    char name[50];
    int rollNumber;
    float marks;
};

// Function to input details of students
void inputStudentDetails(struct Student *students, int numStudents) {
    for (int i = 0; i < numStudents; ++i) {
        printf("Enter details for student %d:\n", i + 1);
        printf("Name: ");
        scanf("%s", students[i].name);  // Assuming names don't have spaces
        printf("Roll Number: ");
        scanf("%d", &students[i].rollNumber);
        printf("Marks: ");
        scanf("%f", &students[i].marks);
    }
}

// Function to write student structures to a binary file individually
void writeToFile(struct Student *students, int numStudents, const char *filename) {
    FILE *file = fopen(filename, "wb");
    if (file == NULL) {
        perror("Error opening file");
        return;
    }

    for (int i = 0; i < numStudents; ++i) {
        fwrite(&students[i], sizeof(struct Student), 1, file);
    }

    fclose(file);
}

int main() {
    int numStudents;

    printf("Enter the number of students: ");
    scanf("%d", &numStudents);

    // Allocate memory for an array of structs
    struct Student *students = (struct Student *)malloc(numStudents * sizeof(struct Student));
    if (students == NULL) {
        perror("Error allocating memory");
        return 1;
    }

    // Input details of students
    inputStudentDetails(students, numStudents);

    // Write student structures to a binary file individually
    writeToFile(students, numStudents, "student_database.bin");

    // Free allocated memory
    free(students);

    printf("Student details written to binary file successfully.\n");

    return 0;
}

Let's go through the code step by step to understand its functionality:

#include <stdio.h>

This line includes the standard input/output library, which provides functions like printf and scanf.

// Define the structure for a student
struct Student {
    char name[50];
    int rollNumber;
    float marks;
};

This defines a structure named Student with three members: name (a character array to store the student's name), rollNumber (an integer to store the roll number), and marks (a float to store the student's marks).

// Function to input details of students
void inputStudentDetails(struct Student *students, int numStudents) {
    for (int i = 0; i < numStudents; ++i) {
        printf("Enter details for student %d:\n", i + 1);
        printf("Name: ");
        scanf("%s", students[i].name);
        printf("Roll Number: ");
        scanf("%d", &students[i].rollNumber);
        printf("Marks: ");
        scanf("%f", &students[i].marks);
    }
}

This function, inputStudentDetails, takes an array of Student structures (students) and the number of students (numStudents). It then uses a loop to input details for each student by prompting the user for the name, roll number, and marks.

// Function to write student structures to a binary file individually
void writeToFile(struct Student *students, int numStudents, const char *filename) {
    FILE *file = fopen(filename, "wb");
    if (file == NULL) {
        perror("Error opening file");
        return;
    }

    for (int i = 0; i < numStudents; ++i) {
        fwrite(&students[i], sizeof(struct Student), 1, file);
    }

    fclose(file);
}

This function, writeToFile, takes an array of Student structures (students), the number of students (numStudents), and a filename as parameters. It opens a file with the specified filename in binary write mode ("wb"). If the file opening fails, it prints an error message using perror and returns from the function.

Inside the function, there's a loop that iterates over each student in the array and uses fwrite to write the student structure to the file. The third argument of fwrite is set to 1 because we are writing one structure at a time. The size of each structure is calculated using sizeof(struct Student).

int main() {
    int numStudents;

    printf("Enter the number of students: ");
    scanf("%d", &numStudents);

    // Allocate memory for an array of structs
    struct Student *students = (struct Student *)malloc(numStudents * sizeof(struct Student));
    if (students == NULL) {
        perror("Error allocating memory");
        return 1;
    }

    // Input details of students
    inputStudentDetails(students, numStudents);

    // Write student structures to a binary file individually
    writeToFile(students, numStudents, "student_database.bin");

    // Free allocated memory
    free(students);

    printf("Student details written to binary file successfully.\n");

    return 0;
}

In the main function, the program begins by prompting the user to enter the number of students. It then dynamically allocates memory for an array of Student structures using malloc. If the memory allocation fails, it prints an error message and exits the program with a return value of 1.

The inputStudentDetails function is then called to gather details for each student from the user.

Finally, the writeToFile function is called to write each student structure to a binary file named "student_database.bin." After writing the data, the dynamically allocated memory is freed using free.

The program concludes by printing a success message and returning 0 from the main function, indicating successful execution.

Here's a program that opens the binary file created by the previous program, reads all structures into an array, takes a roll number from the user, finds the student from the array, and outputs details of that student to the console. It continues to take roll numbers until the user types "done":

#include <stdio.h>

// Define the structure for a student
struct Student {
    char name[50];
    int rollNumber;
    float marks;
};

// Function to read student structures from a binary file individually
void readFromFile(struct Student *students, int numStudents, const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (file == NULL) {
        perror("Error opening file");
        return;
    }

    for (int i = 0; i < numStudents; ++i) {
        fread(&students[i], sizeof(struct Student), 1, file);
    }

    fclose(file);
}

// Function to find and display details of a student by roll number
void findAndDisplayStudent(struct Student *students, int numStudents, int rollNumber) {
    for (int i = 0; i < numStudents; ++i) {
        if (students[i].rollNumber == rollNumber) {
            printf("Student found!\n");
            printf("Name: %s\n", students[i].name);
            printf("Roll Number: %d\n", students[i].rollNumber);
            printf("Marks: %.2f\n", students[i].marks);
            return; // Student found, exit the function
        }
    }

    // If loop completes, the student was not found
    printf("Student with Roll Number %d not found.\n", rollNumber);
}

int main() {
    int numStudents;

    printf("Enter the number of students: ");
    scanf("%d", &numStudents);

    // Allocate memory for an array of structs
    struct Student *students = (struct Student *)malloc(numStudents * sizeof(struct Student));
    if (students == NULL) {
        perror("Error allocating memory");
        return 1;
    }

    // Read student structures from the binary file individually
    readFromFile(students, numStudents, "student_database.bin");

    // Take roll numbers until the user types "done"
    while (1) {
        int rollNumber;
        printf("Enter a roll number (type 'done' to exit): ");
        if (scanf("%d", &rollNumber) != 1) {
            // Handle invalid input
            printf("Invalid input. Exiting.\n");
            break;
        }

        if (rollNumber == -1) {
            // Exit the loop if the user types -1
            break;
        }

        // Find and display details of the student
        findAndDisplayStudent(students, numStudents, rollNumber);
    }

    // Free allocated memory
    free(students);

    return 0;
}

Let's break down the program step by step:

#include <stdio.h>

This line includes the standard input/output library, which provides functions like printf and scanf.

// Define the structure for a student
struct Student {
    char name[50];
    int rollNumber;
    float marks;
};

This defines a structure named Student with three members: name (a character array to store the student's name), rollNumber (an integer to store the roll number), and marks (a float to store the student's marks).

// Function to read student structures from a binary file individually
void readFromFile(struct Student *students, int numStudents, const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (file == NULL) {
        perror("Error opening file");
        return;
    }

    for (int i = 0; i < numStudents; ++i) {
        fread(&students[i], sizeof(struct Student), 1, file);
    }

    fclose(file);
}

This function, readFromFile, takes an array of Student structures (students), the number of students (numStudents), and a filename as parameters. It opens a binary file with the specified filename in read mode ("rb"). If the file opening fails, it prints an error message using perror and returns from the function.

Inside the function, there's a loop that iterates over each student in the array. It uses fread to read the student structure from the file into the array. The third argument of fread is set to 1 because we are reading one structure at a time. The size of each structure is calculated using sizeof(struct Student).

// Function to find and display details of a student by roll number
void findAndDisplayStudent(struct Student *students, int numStudents, int rollNumber) {
    for (int i = 0; i < numStudents; ++i) {
        if (students[i].rollNumber == rollNumber) {
            printf("Student found!\n");
            printf("Name: %s\n", students[i].name);
            printf("Roll Number: %d\n", students[i].rollNumber);
            printf("Marks: %.2f\n", students[i].marks);
            return; // Student found, exit the function
        }
    }

    // If loop completes, the student was not found
    printf("Student with Roll Number %d not found.\n", rollNumber);
}

This function, findAndDisplayStudent, takes an array of Student structures (students), the number of students (numStudents), and a roll number as parameters. It searches for a student with the given roll number in the array and displays their details if found.

int main() {
    int numStudents;

    printf("Enter the number of students: ");
    scanf("%d", &numStudents);

    // Allocate memory for an array of structs
    struct Student *students = (struct Student *)malloc(numStudents * sizeof(struct Student));
    if (students == NULL) {
        perror("Error allocating memory");
        return 1;
    }

    // Read student structures from the binary file individually
    readFromFile(students, numStudents, "student_database.bin");

    // Take roll numbers until the user types "done"
    while (1) {
        int rollNumber;
        printf("Enter a roll number (type 'done' to exit): ");
        if (scanf("%d", &rollNumber) != 1) {
            // Handle invalid input
            printf("Invalid input. Exiting.\n");
            break;
        }

        if (rollNumber == -1) {
            // Exit the loop if the user types -1
            break;
        }

        // Find and display details of the student
        findAndDisplayStudent(students, numStudents, rollNumber);
    }

    // Free allocated memory
    free(students);

    return 0;
}

In the main function, the program starts by prompting the user to enter the number of students. It then dynamically allocates memory for an array of Student structures using malloc. If the memory allocation fails, it prints an error message and exits the program with a return value of 1.

The readFromFile function is then called to read each student structure individually from the binary file into the array.

The program enters a loop where it continuously takes roll numbers from the user until the user types "done" or enters -1. It uses scanf to read integer input, and if the input is not an integer, it prints an error message and exits the loop. If the user types -1, the loop also exits.

For each valid roll number, the findAndDisplayStudent function is called to search for and display details of the corresponding student.

The loop continues until the user types "done" or -1.

Finally, the dynamically allocated memory is freed using free. The program concludes by returning 0 from the main function, indicating successful execution.