What We Are Building
A Student Grade Manager for a class of 5 students with 5 subjects each. The program will:
- Store 5 student names and their marks in 5 subjects
- Calculate each student's total marks and average
- Assign a letter grade (A, B, C, D, F) based on the average
- Find the class topper — the student with the highest average
- Find the highest and lowest mark in the entire class
- Print a neat formatted report card table
Each of these jobs is a separate function. That's the key — split the work into small pieces, one function per job.
Concepts used in this project:
- 1D arrays — store totals, averages, one value per student
- 2D arrays — marks[5][5] — row = student, column = subject
- 2D string array — names[5][20] — store 5 student names
- Functions — 7 functions, each doing one job
- Loops — nested loops to process every mark in the grid
Project Structure — 7 Functions
Before writing any code, plan which functions you need. Good rule: one function = one job. If a function does two different things, split it into two functions.
The 7 functions in this project
getGrade() only needs one number (the average) and gives back one character. That's a simple, clean function. Planning stops you from writing one huge messy function that does everything.Complete Program — Read Every Line
#include <stdio.h> #include <string.h> /* ── Constants ─────────────────────────────────────────── */ #define STUDENTS 5 #define SUBJECTS 5 /* ── Global arrays — shared by all functions ─────────── */ char names[STUDENTS][20]; /* student names */ int marks[STUDENTS][SUBJECTS]; /* marks grid */ int totals[STUDENTS]; /* total per student */ float avg[STUDENTS]; /* average per student */ /* ── Function prototypes ─────────────────────────────── */ void inputData(void); void calcTotals(void); void calcAverages(void); char getGrade(float average); int findTopper(void); void printReport(void); /* ═══════════════════════════════════════════════════════ MAIN — calls functions in order, does nothing itself ═══════════════════════════════════════════════════════ */ int main() { printf("=== STUDENT GRADE MANAGER ===\n\n"); inputData(); /* Step 1: get names and marks */ calcTotals(); /* Step 2: add up each student's marks */ calcAverages(); /* Step 3: divide to get averages */ printReport(); /* Step 4: show the report card */ return 0; } /* ═══════════════════════════════════════════════════════ INPUT — reads all student names and marks ═══════════════════════════════════════════════════════ */ void inputData(void) { int i, j; char subjects[SUBJECTS][10] = { "Maths", "Science", "English", "History", "C Prog" }; for (i = 0; i < STUDENTS; i++) { printf("Student %d name: ", i + 1); scanf("%s", names[i]); printf("Enter marks for %s:\n", names[i]); for (j = 0; j < SUBJECTS; j++) { printf(" %-10s: ", subjects[j]); scanf("%d", &marks[i][j]); } printf("\n"); } } /* ═══════════════════════════════════════════════════════ CALC TOTALS — adds up all marks for each student ═══════════════════════════════════════════════════════ */ void calcTotals(void) { int i, j; for (i = 0; i < STUDENTS; i++) { totals[i] = 0; for (j = 0; j < SUBJECTS; j++) totals[i] += marks[i][j]; } } /* ═══════════════════════════════════════════════════════ CALC AVERAGES — divides total by number of subjects ═══════════════════════════════════════════════════════ */ void calcAverages(void) { int i; for (i = 0; i < STUDENTS; i++) avg[i] = (float)totals[i] / SUBJECTS; } /* ═══════════════════════════════════════════════════════ GET GRADE — takes average, returns A/B/C/D/F ═══════════════════════════════════════════════════════ */ char getGrade(float average) { if (average >= 90) return 'A'; else if (average >= 75) return 'B'; else if (average >= 55) return 'C'; else if (average >= 35) return 'D'; else return 'F'; } /* ═══════════════════════════════════════════════════════ FIND TOPPER — returns index of student with highest avg ═══════════════════════════════════════════════════════ */ int findTopper(void) { int i, topIdx = 0; for (i = 1; i < STUDENTS; i++) if (avg[i] > avg[topIdx]) topIdx = i; return topIdx; } /* ═══════════════════════════════════════════════════════ PRINT REPORT — formatted report card table ═══════════════════════════════════════════════════════ */ void printReport(void) { int i, j, topIdx; int highest = marks[0][0], lowest = marks[0][0]; /* ── Find highest and lowest mark in class ───────── */ for (i = 0; i < STUDENTS; i++) for (j = 0; j < SUBJECTS; j++) { if (marks[i][j] > highest) highest = marks[i][j]; if (marks[i][j] < lowest) lowest = marks[i][j]; } /* ── Print header ────────────────────────────────── */ printf("\n"); printf("============================================================\n"); printf(" STUDENT REPORT CARD\n"); printf("============================================================\n"); printf("%-12s M1 M2 M3 M4 M5 Total Avg Grade\n", "Name"); printf("------------------------------------------------------------\n"); /* ── Print each student row ──────────────────────── */ for (i = 0; i < STUDENTS; i++) { printf("%-12s", names[i]); for (j = 0; j < SUBJECTS; j++) printf("%4d", marks[i][j]); printf(" %5d %6.1f %c\n", totals[i], avg[i], getGrade(avg[i])); } /* ── Summary ─────────────────────────────────────── */ printf("------------------------------------------------------------\n"); topIdx = findTopper(); printf("Class Topper : %s (%.1f avg)\n", names[topIdx], avg[topIdx]); printf("Highest Mark : %d\n", highest); printf("Lowest Mark : %d\n", lowest); printf("============================================================\n"); }
Sample Run — What It Looks Like
=== STUDENT GRADE MANAGER ===
Student 1 name: Ananta
Enter marks for Ananta:
Maths : 85
Science : 90
English : 78
History : 88
C Prog : 95
Student 2 name: Priya
Enter marks for Priya:
Maths : 92
Science : 88
English : 95
History : 82
C Prog : 90
Student 3 name: Rahul
Enter marks for Rahul:
Maths : 60
Science : 55
English : 70
History : 65
C Prog : 58
Student 4 name: Vikram
Enter marks for Vikram:
Maths : 78
Science : 82
English : 75
History : 88
C Prog : 80
Student 5 name: Sneha
Enter marks for Sneha:
Maths : 96
Science : 94
English : 98
History : 92
C Prog : 97
============================================================
STUDENT REPORT CARD
============================================================
Name M1 M2 M3 M4 M5 Total Avg Grade
------------------------------------------------------------
Ananta 85 90 78 88 95 436 87.2 B
Priya 92 88 95 82 90 447 89.4 B
Rahul 60 55 70 65 58 308 61.6 C
Vikram 78 82 75 88 80 403 80.6 B
Sneha 96 94 98 92 97 477 95.4 A
------------------------------------------------------------
Class Topper : Sneha (95.4 avg)
Highest Mark : 98
Lowest Mark : 55
============================================================
Each Function Explained
inputData() — outer loop runs 5 times (one per student). For each student: read their name with scanf("%s", names[i]), then the inner loop reads 5 marks into marks[i][0] through marks[i][4]. The local subjects[] array is just for the prompt labels.
calcTotals() — nested loop. Outer: student index i. First set totals[i] = 0. Inner: add each of the 5 subject marks. Result: totals[0] = Ananta's total, totals[1] = Priya's total, etc.
calcAverages() — simple loop. Divides each total by SUBJECTS (5). The cast (float)totals[i] is important — without it, integer division would give 87 instead of 87.2.
getGrade(float average) — the cleanest function. Takes one number, returns one character. A chain of if-else if checks which range the average falls in. Called once per student inside printReport().
findTopper() — starts by assuming student 0 is the topper (topIdx = 0). Loops through students 1–4. If any student's average beats the current best, update topIdx. Returns the index — not the name, not the average. The caller uses the index to look up whatever they need.
printReport() — the only function that prints. First finds highest and lowest marks using a nested loop. Then prints the header, then loops through each student printing a formatted row — calling getGrade() right inside printf to get the letter grade. Finally calls findTopper() for the summary.
printReport() calls both getGrade() and findTopper() inside itself. main() never calls getGrade or findTopper directly — it doesn't need to. This is the right way to structure a program. Each function knows only what it needs to know.What This Project Teaches
- Global arrays —
marks[][],totals[],avg[],names[][]are declared outside all functions so every function can access them without passing parameters. This is the simplest approach for a small project. - void functions —
inputData(),calcTotals(),calcAverages(),printReport()all usevoidbecause they work with global arrays — they don't need to return anything. - Functions that return values —
getGrade()returns achar,findTopper()returns anint. These are pure utility functions — give input, get output, no side effects. - Functions calling functions —
printReport()callsgetGrade()andfindTopper().main()stays clean and simple. - The (float) cast — without
(float)totals[i] / SUBJECTS, C does integer division and you get 87 instead of 87.2. Always cast when you need decimals.
#define STUDENTS 5 to any number), adding a function to sort students by rank, saving results to a file, or adding a subject-wise class average row at the bottom. All of these are just one more function each.Project Checklist
- I understand why the arrays are declared globally — so all functions can share them
- inputData() — outer loop = students, inner loop = subjects, reads marks[i][j]
- calcTotals() — nested loop adds all 5 marks for each student into totals[i]
- calcAverages() — (float) cast is needed to get decimal average, not integer
- getGrade() — takes one float, returns one char. Clean single-purpose function.
- findTopper() — starts at index 0, updates topIdx when a higher average is found
- printReport() — calls getGrade() and findTopper() inside itself
- I typed out the code and ran it successfully