Building a simple file based record keeping system in C
Greetings(Namaste). Earlier this week, one of my sister requested to help her do her computer science project from her school. The project was to be done in C. And, was told not to use AI for the project, to be specific, was told that her marks will be deducted if she was found using help from AI tools(According to her, there are various AI detection tools). Her project was like this:
Define a structure student with members:
sid, name, address, marks of sub1, sub2, sub3, total and percent.
Write a menu driven program to write, read, append and
exit successive records to/from a data file.
I was instantly ready to help her. I have created the simple Student record keeping system. I will guide you step by step how to do this.
Understanding our project: Student record keeping system
First of all, we have to create a sturcture to store record of students such as sid, name, address, etc. in the program.
Secondly, we will allow users to interact with our system to perform one of four actions:
1. Write student record to file (Warning: Will overwrite existing file content).
2. Read contents(student's record) from file.
3. Append student record to file (will add record at the end, won't overwrite).
4. Exit the program.
Comiler for C
We need a compiler to comile our C program. Download appropriate compiler. We have used gcc compiler, available on both linux/mac-os based system.
For windows user, you can use:
- MinGW-w64/WinLibs for a GCC-based compiler on Windows.
- Use code editors like Code::Blocks, Dev-C++ or Visual Studio(Visual Studio is different from Visual Studio Code) that has in-build compiler.
Creating folder and files
First of all, create a folder using terminal for linux/mac-os users or command line (you can also use a file manager to do this). And inside that folder make a C file and text file (we will store student's record on this text file).
mkdir record_keeper
cd record_keeper
touch index.c
touch records.txt
# for windows user
type nul > index.c
type nul > records.txt
Developing our system
Open index.c file in your favorite code editor.
First, lets create sturcture named Student in our program with empty main() function. We have 8 fields inside Student structure with respective types.
// preprocessor derictives (usage will be explained at final code: look at comments)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Student
{
int id;
char name[50];
char address[50];
float sub1;
float sub2;
float sub3;
float total;
float percentage;
};
int main(){
return 0;
}
Now, we will update main() function along with function definition writeToFile(), readFromFile() and appendToFile() as shown below:
// function declarations, we will define it later
void writeToFile(char filepath[50]);
void readFromFile(char filepath[50]);
void appendToFile(char filepath[50]);
int main()
{
printf("\n"); // new line
printf("Welcome to student record keeper: (Developer: My Sister): \n \n ");
int choice; // variable to store choice from user
while (1)
{
printf("\n"); // new line
printf("Please enter number for one of the given choice: \n 1: Create new record \n 2: Read records \n 3: Append record \n 4: Exit \n");
scanf("%d", &choice);
printf("\n"); // new line
switch (choice)
{
case 1:
printf("Choice 1 (Write) selected.\n\n");
writeToFile("records.txt");
break;
case 2:
printf("Choice 2 (Read) selected.\n\n");
readFromFile("records.txt");
break;
case 3:
printf("Choice 3 (Append) selected.\n\n");
appendToFile("records.txt");
break;
case 4:
printf("Choice 4 (Exit) selected.\n\n");
exit(0);
default:
printf("Invalid choice!!! \n");
break;
}
}
return 0;
}
We have used printf("\n"); and \n in multiple places so that UI for user looks clean in command line. Also, we have created a while loop, that will terminate only when user enters number 4.
Now, we will add removeEnter() and handleUserData() functions above three function definitions we added before. Function removeEnter() is an utility function to remove "\n" from a string (we got through user input) and handleUserData() function is used to get data for students from user.
void removeEnter(char* str){
size_t len = strlen(str);
if (len > 0 && str[len - 1] == '\n') {
str[len - 1] = '\0';
}
}
void handleUserData(char *str)
{
struct Student s1;
printf("Please enter your details: \n");
printf("Enter your id: ");
scanf("%d", &s1.id);
getchar();
printf("Enter your name: ");
fgets(s1.name, sizeof(s1.name), stdin);
removeEnter(s1.name);
printf("Enter your address: ");
fgets(s1.address, sizeof(s1.address), stdin);
removeEnter(s1.address);
printf("Enter marks for s1: ");
scanf("%f", &s1.sub1);
printf("Enter marks for s2: ");
scanf("%f", &s1.sub2);
printf("Enter marks for s3: ");
scanf("%f", &s1.sub3);
s1.total = s1.sub1 + s1.sub2 + s1.sub3;
s1.percentage = (s1.total / 300.0) * 100.0; // assuming total is 100 for each subject
sprintf(str, "Na: %s, Ad: %s, m1: %.2f, m2: %.2f, m3: %.2f, tot: %.2f per: %.2f%%", s1.name, s1.address, s1.sub1, s1.sub2, s1.sub3, s1.total, s1.percentage);
}
handleUserData(char *str)takes pointer to char type with namestras parameter.struct Student s1: We declare a variable of type struct Student.fgets(s1.name, sizeof(s1.name), stdin): fgets() to get string from user, becuase normalscanf()won't work properly for the string with whitespaces.sprintf(str, "Na: %s", s1.name): write string content tostr, ie. writes "Na: something" tostr.
Now, we will define three functions: writeToFile(), readFromFile() and appendToFile() below main() function. Among these three, we will define writeToFile() function first.
void writeToFile(char filepath[50])
{
FILE *fp;
char str[500];
fp = fopen(filepath, "w");
if (fp == NULL)
{
printf("Can't open file");
return;
}
handleUserData(str);
fputs(str, fp);
fputs("\n", fp);
printf("\n%s written to %s successfully.\n", str, filepath);
fclose(fp);
}
FILE *fp: create pointer of type FILE.fp = fopen(filepath, "w"): opens file with "w" (write mode). Write mode writes to a file from scratch (overwrites existing conent) and creates file if doesn't existfputs(str, fp): writes the content ofstrvariable to file pointerfp.fputs("\n", fp): fputs() doesn't add newline to the file, so have to do this manually.fclose(fp): closes the file
Now, we will define readFromFile()
void readFromFile(char filepath[50])
{
FILE *fp;
char *ch;
fp = fopen(filepath, "r");
if (fp == NULL)
{
printf("Can't open file \n");
return;
}
while (fgets(ch, 500, fp) != NULL)
{
printf("%s", ch);
}
fclose(fp);
}
fgets(ch, 500, fp) is the standard way to read a line of text from a file.
ch (The Buffer): This is the character array (string) where the data from the file will be stored.
500 (The Limit): This tells the function to read a maximum of 499 characters. The 500th spot is reserved for the null terminator (\0) to ensure the string is valid.
fp (The File Pointer): This is the "handle" to the file you opened using fopen().
Now, lets define appendToFile().
void appendToFile(char filepath[50])
{
FILE *fp;
char str[500];
fp = fopen(filepath, "a");
if (fp == NULL)
{
printf("Can't open file");
return;
}
handleUserData(str);
fputs(str, fp);
fputs("\n", fp);
printf("\n%s appended to %s successfully.\n", str, filepath);
fclose(fp);
}
fp = fopen(filepath, "a"): opens file in append mode("a" means append mode). In append mode, new contents are added exactly where the file ends. Also, it will create file with filepath, if file doesn't exist.
Our final program will look like this:
#include <stdio.h> // For: printf, scanf, getchar, sprintf, fputs, fgets, fopen, fclose, and FILE structure.
#include <stdlib.h> // For: exit() function used to terminate the program in the switch case.
#include <string.h> // For: strlen() used in the removeEnter function to calculate string length.
struct Student
{
int id;
char name[50];
char address[50];
float sub1;
float sub2;
float sub3;
float total;
float percentage;
};
void removeEnter(char* str){
size_t len = strlen(str);
if (len > 0 && str[len - 1] == '\n') {
str[len - 1] = '\0';
}
}
void handleUserData(char *str)
{
struct Student s1;
printf("Please enter your details: \n");
printf("Enter your id: ");
scanf("%d", &s1.id);
getchar();
printf("Enter your name: ");
fgets(s1.name, sizeof(s1.name), stdin);
removeEnter(s1.name);
printf("Enter your address: ");
fgets(s1.address, sizeof(s1.address), stdin);
removeEnter(s1.address);
printf("Enter marks for s1: ");
scanf("%f", &s1.sub1);
printf("Enter marks for s2: ");
scanf("%f", &s1.sub2);
printf("Enter marks for s3: ");
scanf("%f", &s1.sub3);
s1.total = s1.sub1 + s1.sub2 + s1.sub3;
s1.percentage = (s1.total / 300.0) * 100.0; // assuming total is 100 for each subject
sprintf(str, "Na: %s, Ad: %s, m1: %.2f, m2: %.2f, m3: %.2f, tot: %.2f per: %.2f%%", s1.name, s1.address, s1.sub1, s1.sub2, s1.sub3, s1.total, s1.percentage);
}
// function declarations, we will define it later
void writeToFile(char filepath[50]);
void readFromFile(char filepath[50]);
void appendToFile(char filepath[50]);
int main()
{
printf("\n"); // new line
printf("Welcome to student record keeper: (Developer: My Sister): \n \n ");
int choice; // variable to store choice from user
while (1)
{
printf("\n"); // new line
printf("Please enter number for one of the given choice: \n 1: Create new record \n 2: Read records \n 3: Append record \n 4: Exit \n");
scanf("%d", &choice);
printf("\n"); // new line
switch (choice)
{
case 1:
printf("Choice 1 (Write) selected.\n\n");
writeToFile("records.txt");
break;
case 2:
printf("Choice 2 (Read) selected.\n\n");
readFromFile("records.txt");
break;
case 3:
printf("Choice 3 (Append) selected.\n\n");
appendToFile("records.txt");
break;
case 4:
printf("Choice 4 (Exit) selected.\n\n");
exit(0);
default:
printf("Invalid choice!!! \n");
break;
}
}
return 0;
}
void writeToFile(char filepath[50])
{
FILE *fp;
char str[500];
fp = fopen(filepath, "w");
if (fp == NULL)
{
printf("Can't open file");
return;
}
handleUserData(str);
fputs(str, fp);
fputs("\n", fp);
printf("\n%s written to %s successfully.\n", str, filepath);
fclose(fp);
}
void readFromFile(char filepath[50])
{
FILE *fp;
char *ch;
fp = fopen(filepath, "r");
if (fp == NULL)
{
printf("Can't open file \n");
return;
}
while (fgets(ch, 500, fp) != NULL)
{
printf("%s", ch);
}
fclose(fp);
}
void appendToFile(char filepath[50])
{
FILE *fp;
char str[500];
fp = fopen(filepath, "a");
if (fp == NULL)
{
printf("Can't open file");
return;
}
handleUserData(str);
fputs(str, fp);
fputs("\n", fp);
printf("\n%s appended to %s successfully.\n", str, filepath);
fclose(fp);
}
Run the program. You might get warnings (some modern compiler may warn you), but you can simply ignore those warnings for now.
gcc index.c
./a.out
Initial output will look like this:
Welcome to student record keeper: (Developer: My Sister):
Please enter number for one of the given choice:
1: Create new record
2: Read records
3: Append record
4: Exit
Play around with this program and explore options from 1 to 4.