Practical Guide to C Language Pointers: Student Grade Management System – Pointer Enhanced Version (Menu + Struct Array + Sorting/Querying/Statistics)

โญ 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)

  1. New Feature: Sort by name (in dictionary order) in ascending order.
  2. New Feature: Fuzzy query by name (substring matching).
  3. Export Feature: Copy failing students to array B and return the count (experience “pointer + return count”).
  4. Comprehensive: First sort by grade in descending order, then print the top N students (N can be input).
  5. 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”

Leave a Comment