Project Overview & Topic Map
Every fundamental concept below appears in this ONE program — nothing here needs a linked list, stack, queue, or tree. The goal is breadth across the basics, not a new data structure.
| Concept | Where it appears |
|---|---|
| Structures | struct Student — roll, name, marks, average, grade |
| Arrays | students[] array of structs; marks[3] inside each struct |
| Pointers | addStudent() writes through Student *s |
| Strings | name[40], read with %[^\n] |
| if-else | Grade calculation ladder (A/B/C/F) |
| break | Stops searchByRoll() the moment a match is found |
| continue | Skips counting a failed student as "pass" in the summary loop |
| Storage classes | const pass mark, static call counter, global studentCount |
| Files | saveToFile() writes all records with fprintf |
| Functions | One function per operation, called from a menu |
Struct, Global Array & const (Storage/Qualifier Basics)
PASS_MARK is declared const — its value can never change after this line, protecting the pass threshold from accidental edits anywhere else in the file. students[] and studentCount are global — declared outside any function, so every function in the file can see and use them directly.
#include <stdio.h> #include <string.h> #define MAX_STUDENTS 5 const float PASS_MARK = 40.0; // cannot be changed anywhere after this typedef struct { int roll; char name[40]; float marks[3]; // 3 subjects float average; char grade; } Student; Student students[MAX_STUDENTS]; // global array — visible to every function below int studentCount = 0; // global — tracks how many slots are filled
Adding a Student — Pointer, static, and if-else
s is a pointer to the new student's slot in the array — every field is written through s->, directly into the real array, not a copy. addCallCount is static: unlike a normal local variable, it keeps its value between calls instead of resetting to 0 every time the function runs.
void addStudent() { static int addCallCount = 0; // persists across every call, private to this function addCallCount++; if (studentCount >= MAX_STUDENTS) { printf("Student list full.\n"); return; } Student *s = &students[studentCount]; // pointer to the new slot printf("Enter roll number: "); scanf("%d", &s->roll); printf("Enter name: "); scanf(" %[^\n]", s->name); // reads a full name with spaces float total = 0; for (int i = 0; i < 3; i++) { printf("Enter marks for subject %d: ", i + 1); scanf("%f", &s->marks[i]); total += s->marks[i]; } s->average = total / 3; if (s->average >= 90) s->grade = 'A'; else if (s->average >= 75) s->grade = 'B'; else if (s->average >= PASS_MARK) s->grade = 'C'; else s->grade = 'F'; studentCount++; printf("Student added. (addStudent called %d time(s) so far)\n", addCallCount); }
addCallCount stays private to addStudent() — no other function can see or accidentally modify it, unlike studentCount which any function in the file can touch.Search & Summary — break, continue, and Strings
searchByRoll() uses break the instant it finds a match — continuing to check the rest of the array would be wasted work. passFailSummary() uses continue to skip the "pass" counter for failing students without needing an extra else block.
void searchByRoll() { int roll, found = 0; printf("Enter roll number to search: "); scanf("%d", &roll); for (int i = 0; i < studentCount; i++) { if (students[i].roll == roll) { printf("Found: %s | Average: %.2f | Grade: %c\n", students[i].name, students[i].average, students[i].grade); found = 1; break; // stop immediately — no need to keep scanning } } if (!found) printf("Roll number not found.\n"); } void passFailSummary() { int pass = 0, fail = 0; for (int i = 0; i < studentCount; i++) { if (students[i].grade == 'F') { fail++; continue; // skip the pass++ below, move to the next student } pass++; } printf("Passed: %d | Failed: %d\n", pass, fail); }
name is a plain char array, comparing two names for equality would use strcmp(students[i].name, target) == 0 — never == directly, which would compare addresses instead of the actual text.Saving Records to a File
Same file-writing pattern as the Hotel, Library, Hospital, and Banking projects — loop through the array, write one CSV line per record with fprintf.
void saveToFile() { FILE *fp = fopen("students.txt", "w"); if (!fp) { printf("Error opening file.\n"); return; } for (int i = 0; i < studentCount; i++) { fprintf(fp, "%d,%s,%.2f,%c\n", students[i].roll, students[i].name, students[i].average, students[i].grade); } fclose(fp); printf("Saved to students.txt\n"); } void displayAll() { printf("\n%-6s %-16s %-10s %-6s\n", "Roll", "Name", "Average", "Grade"); for (int i = 0; i < studentCount; i++) { printf("%-6d %-16s %-10.2f %-6c\n", students[i].roll, students[i].name, students[i].average, students[i].grade); } }
The Main Menu
Same thin main() pattern as the other projects — a do-while loop with a switch routing each choice to the right function.
int main() { int choice; do { printf("\n===== STUDENT RESULT MANAGEMENT =====\n"); printf("1. Add Student\n"); printf("2. Display All\n"); printf("3. Search by Roll\n"); printf("4. Pass/Fail Summary\n"); printf("5. Save to File\n"); printf("6. Exit\n"); printf("Enter choice: "); scanf("%d", &choice); switch (choice) { case 1: addStudent(); break; case 2: displayAll(); break; case 3: searchByRoll(); break; case 4: passFailSummary(); break; case 5: saveToFile(); break; case 6: printf("Exiting... Goodbye!\n"); break; default: printf("Invalid choice.\n"); } } while (choice != 6); return 0; }
===== STUDENT RESULT MANAGEMENT ===== 1. Add Student 2. Display All 3. Search by Roll 4. Pass/Fail Summary 5. Save to File 6. Exit Enter choice: 1 Enter roll number: 101 Enter name: Aditi Sharma Enter marks for subject 1: 88 Enter marks for subject 2: 92 Enter marks for subject 3: 79 Student added. (addStudent called 1 time(s) so far) Enter choice: 1 Enter roll number: 102 Enter name: Rohan Gupta Enter marks for subject 1: 30 Enter marks for subject 2: 25 Enter marks for subject 3: 35 Student added. (addStudent called 2 time(s) so far) Enter choice: 2 Roll Name Average Grade 101 Aditi Sharma 86.33 B 102 Rohan Gupta 30.00 F Enter choice: 4 Passed: 1 | Failed: 1 Enter choice: 6 Exiting... Goodbye!
Ways to Extend This Project
Every upgrade below still avoids data structures, staying within the same fundamentals-first spirit:
- Load from file on startup — read
students.txtback withfscanf - Search by name — loop +
strcmp()instead of comparing roll numbers - Update a record — find by roll (reusing the search pattern), then overwrite fields through a pointer
- More subjects — increase the
marks[3]array size and adjust the average calculation - extern practice — split the file into
main.candstudent.c, declaring shared globals withextern
Project Checklist
- I understand the Student struct and the global students[] array
- I can explain why PASS_MARK is declared const
- I can trace addStudent() writing through the pointer s
- I understand how static addCallCount differs from a normal local variable
- I can trace the if-else grade ladder
- I understand why break stops searchByRoll() immediately
- I understand why continue skips the pass++ line for failing students
- I understand how saveToFile() writes each student as a CSV line
- I compiled and ran the full program myself