โญ Practical Guide to C Language Pointers: Student Grade Management System – Pointer Enhanced Version (Menu + Struct Array + Sorting/Querying/Statistics)
Author: IoT Smart Academy
In the previous chapter, we created the “IoT Sensor Monitoring System – Enhanced Version”. In this article, we will apply the same concept of “struct + array + pointer parameters” to the most commonly used in teaching – the Student Grade Management System (Pointer Enhanced Version).
Objective: The code should run directly, the menu should be clear, and all functions should use pointers to modify the “real data”.
๐งญ Function List (Menu)
- 1 Enter Student
- 2 Show All
- 3 Query by Student ID / 4 Query by Name
- 5 Update Grade (by Student ID)
- 6 Delete Student (by Student ID)
- 7 Sort by Grade (Descending) / 8 Sort by Grade (Ascending)
- 9 Sort by Student ID (Ascending)
- 10 Statistics: Highest/Lowest/Average/Pass Rate
- 11 Grade Range Filtering (e.g., 60โ80)
- 12 Batch Bonus (Curve Adjustment: All + offset)
- 0 Exit
Design Points: All functions that modify data use pointer parameters; read-only functions use
<span>const</span>to indicate “will not modify”.
๐ป Complete Runnable Code (Copy and Use)
#include <stdio.h>
#include <string.h>
#define MAX_STU 300
/* โโ Data Structure โโ */
typedef struct {
int id; // Student ID
char name[20]; // Name (English or Pinyin without spaces, for beginners)
float score; // Grade
} Student;
typedef struct {
Student arr[MAX_STU];
int count; // Current number of students
} StudentDB;
/* โโ Function Declarations โโ */
void initDB(StudentDB *db);
int menu();
void addStudents(StudentDB *db);
void showAll(const StudentDB *db);
Student* findById(StudentDB *db, int id);
int findByNameFirst(const StudentDB *db, const char *name); // Returns index, -1 if not found
void updateById(StudentDB *db);
void deleteById(StudentDB *db);
void sortByScoreDesc(StudentDB *db);
void sortByScoreAsc(StudentDB *db);
void sortByIdAsc(StudentDB *db);
void statistics(const StudentDB *db);
void filterByRange(const StudentDB *db);
void batchBonus(StudentDB *db);
int readInt(const char *tip);
float readFloat(const char *tip);
/* โโ Main Program โโ */
int main() {
StudentDB db;
initDB(&db);
while (1) {
switch (menu()) {
case 1: addStudents(&db); break;
case 2: showAll(&db); break;
case 3: {
int id = readInt("Please enter Student ID:");
Student *p = findById(&db, id);
if (p) {
printf("Found: Student ID=%d Name=%s Grade=%.2f\n", p->id, p->name, p->score);
} else {
printf("Student ID not found.\n");
}
} break;
case 4: {
char key[20];
printf("Please enter Name:");
scanf("%19s", key);
int pos = findByNameFirst(&db, key);
if (pos >= 0) {
printf("Found: Student ID=%d Name=%s Grade=%.2f\n",
db.arr[pos].id, db.arr[pos].name, db.arr[pos].score);
} else {
printf("Name not found.\n");
}
} break;
case 5: updateById(&db); break;
case 6: deleteById(&db); break;
case 7: sortByScoreDesc(&db); break;
case 8: sortByScoreAsc(&db); break;
case 9: sortByIdAsc(&db); break;
case 10: statistics(&db); break;
case 11: filterByRange(&db); break;
case 12: batchBonus(&db); break;
case 0:
printf("System exited, goodbye!\n");
return 0;
default:
printf("Invalid option, please try again.\n");
}
}
}
/* โโ Initialization โโ */
void initDB(StudentDB *db) {
db->count = 0;
}
/* โโ Menu โโ */
int menu() {
int c;
printf("\n===== Student Grade Management System - Pointer Enhanced Version =====\n");
printf("1 Enter Student\n");
printf("2 Show All\n");
printf("3 Query by Student ID\n");
printf("4 Query by Name\n");
printf("5 Update Grade (by Student ID)\n");
printf("6 Delete Student (by Student ID)\n");
printf("7 Sort by Grade Descending\n");
printf("8 Sort by Grade Ascending\n");
printf("9 Sort by Student ID Ascending\n");
printf("10 Statistics (Highest/Lowest/Average/Pass Rate)\n");
printf("11 Grade Range Filtering\n");
printf("12 Batch Bonus (+offset)\n");
printf("0 Exit\n");
printf("=====================================\n");
printf("Please enter option:");
scanf("%d", &c);
return c;
}
/* โโ Input Tools โโ */
int readInt(const char *tip) {
int x;
printf("%s", tip);
scanf("%d", &x);
return x;
}
float readFloat(const char *tip) {
float x;
printf("%s", tip);
scanf("%f", &x);
return x;
}
/* โโ Enter Students โโ */
void addStudents(StudentDB *db) {
int n = readInt("Please enter the number of students to add:");
if (n <= 0) { printf("Number must be greater than 0.\n"); return; }
if (db->count + n > MAX_STU) {
printf("Insufficient capacity, can add %d more students.\n", MAX_STU - db->count);
return;
}
for (int i = 0; i < n; i++) {
Student s;
printf("Please enter Student ID Name Grade (e.g., 1001 Zhang 85.5):\n");
scanf("%d %19s %f", &s.id, s.name, &s.score);
db->arr[db->count++] = s;
}
printf("โ
Added, current total number of students: %d\n", db->count);
}
/* โโ Show All (Read-Only) โโ */
void showAll(const StudentDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
printf("\nIndex\tStudent ID\tName\tGrade\n");
for (int i = 0; i < db->count; i++) {
printf("%d\t%d\t%s\t%.2f\n", i + 1, db->arr[i].id, db->arr[i].name, db->arr[i].score);
}
}
/* โโ Query โโ */
Student* findById(StudentDB *db, int id) {
for (int i = 0; i < db->count; i++) {
if (db->arr[i].id == id) return &db->arr[i];
}
return NULL;
}
int findByNameFirst(const StudentDB *db, const char *name) {
for (int i = 0; i < db->count; i++) {
if (strcmp(db->arr[i].name, name) == 0) return i;
}
return -1;
}
/* โโ Update Grade โโ */
void updateById(StudentDB *db) {
int id = readInt("Please enter the Student ID to update the grade:");
Student *p = findById(db, id);
if (!p) { printf("Student ID not found.\n"); return; }
float sc = readFloat("Please enter new grade:");
p->score = sc;
printf("โ
Updated: Student ID=%d Name=%s New Grade=%.2f\n", p->id, p->name, p->score);
}
/* โโ Delete (Shift and Overwrite) โโ */
void deleteById(StudentDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
int id = readInt("Please enter the Student ID to delete:");
int pos = -1;
for (int i = 0; i < db->count; i++) {
if (db->arr[i].id == id) { pos = i; break; }
}
if (pos == -1) { printf("Student ID not found.\n"); return; }
for (int i = pos; i < db->count - 1; i++) db->arr[i] = db->arr[i + 1];
db->count--;
printf("โ
Deleted Student ID %d, current number of students: %d\n", id, db->count);
}
/* โโ Sorting โโ */
void sortByScoreDesc(StudentDB *db) {
for (int i = 0; i < db->count - 1; i++) {
for (int j = 0; j < db->count - 1 - i; j++) {
if (db->arr[j].score < db->arr[j + 1].score) {
Student t = db->arr[j];
db->arr[j] = db->arr[j + 1];
db->arr[j + 1] = t;
}
}
}
printf("โ
Sorted by grade in descending order.\n");
showAll(db);
}
void sortByScoreAsc(StudentDB *db) {
for (int i = 0; i < db->count - 1; i++) {
for (int j = 0; j < db->count - 1 - i; j++) {
if (db->arr[j].score > db->arr[j + 1].score) {
Student t = db->arr[j];
db->arr[j] = db->arr[j + 1];
db->arr[j + 1] = t;
}
}
}
printf("โ
Sorted by grade in ascending order.\n");
showAll(db);
}
void sortByIdAsc(StudentDB *db) {
for (int i = 0; i < db->count - 1; i++) {
for (int j = 0; j < db->count - 1 - i; j++) {
if (db->arr[j].id > db->arr[j + 1].id) {
Student t = db->arr[j];
db->arr[j] = db->arr[j + 1];
db->arr[j + 1] = t;
}
}
}
printf("โ
Sorted by Student ID in ascending order.\n");
showAll(db);
}
/* โโ Statistics โโ */
void statistics(const StudentDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
float max = db->arr[0].score, min = db->arr[0].score, sum = 0.0f;
int pass = 0;
for (int i = 0; i < db->count; i++) {
float x = db->arr[i].score;
if (x > max) max = x;
if (x < min) min = x;
sum += x;
if (x >= 60.0f) pass++;
}
printf("Number of students: %d\nHighest score: %.2f\nLowest score: %.2f\nAverage score: %.2f\nPass rate: %.2f%%\n",
db->count, max, min, sum / db->count, db->count ? (100.0f * pass / db->count) : 0.0f);
}
/* โโ Range Filtering (Read-Only) โโ */
void filterByRange(const StudentDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
float L = readFloat("Please enter lower limit:");
float R = readFloat("Please enter upper limit:");
if (L > R) { float t = L; L = R; R = t; }
int found = 0;
printf("\n=== Students in the range [%.2f, %.2f] ===\n", L, R);
for (int i = 0; i < db->count; i++) {
float x = db->arr[i].score;
if (x >= L && x <= R) {
printf("%d\t%s\t%.2f\n", db->arr[i].id, db->arr[i].name, x);
found = 1;
}
}
if (!found) printf("No matching records.\n");
}
/* โโ Batch Bonus โโ */
void batchBonus(StudentDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
float off = readFloat("Please enter bonus offset (e.g., +2 / -1.5):");
for (int i = 0; i < db->count; i++) {
db->arr[i].score += off;
if (db->arr[i].score < 0) db->arr[i].score = 0;
if (db->arr[i].score > 100) db->arr[i].score = 100;
}
printf("โ
Batch bonus applied (offset=%.2f, automatically clipped to [0,100]).\n", off);
showAll(db);
}
๐ช Key Points for Classroom Explanation (Easy to Explain)
- To modify original data โ pass address:
<span>StudentDB *db</span>, directly modify the array internally; query returns<span>Student*</span>, use<span>p->score</span>to modify the “real grade”. - **Read-only โ add
<span>const</span>**:<span>showAll(const StudentDB *db)</span>,<span>statistics(const ...)</span>, professional and safe. - Sorting/Range/Statistics: use array templates, replace objects with structs.
- Input Helper Tools:
<span>readInt / readFloat</span>make the main process cleaner, easier for board explanation.
๐งช Suggested Demonstration Use Cases
1 Enter 5 students:
1003 Li 78.5
1001 Zhang 92
1005 Wang 63
1002 Zhao 88.5
1004 Chen 59
2 Show All
7 Sort by Grade Descending
5 Update Grade: Student ID=1004 -> 62
10 Statistics
11 Range Filtering: 60~80
12 Batch Bonus: +2
9 Sort by Student ID Ascending
6 Delete: Student ID=1005
2 Show All
๐งฑ Practical Assignment (Continue on this code)
- New Feature: Sort by name (in dictionary order) in ascending order.
- New Feature: Fuzzy query by name (substring matching).
- Export Feature: Copy failing students to array B and return the count (experience “pointer + return count”).
- Comprehensive: First sort by grade in descending order, then print the top N students (N can be input).
- Bonus Item: Archive/Read the
<span>StudentDB</span>(text/binary) to achieve “still there when opened next time”.
๐ One-Screen Password Card (For Students)
- To modify, pass address:
<span>func(&x)</span>/<span>func(db)</span> - Function uses pointer:
<span>void func(StudentDB *db)</span> - Struct pointer access:
<span>p->score</span>(equivalent to<span>(*p).score</span>) - Array is base address:
<span>db->arr</span>can be passed as a parameter - Read-only parameters add
<span>const</span>, clearly indicating “no data modification”