首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言綜合實戰:學生成績管理系統(鏈表+檔案+排序)

     編輯:關於C語言

專案概覽

「菜鳥修煉」系列壓軸之作:學生成績管理系統,約 600 行代碼,整合單向鏈表增刪改查、檔案持久化、多欄位排序、選單驅動。模組劃分清晰,適合作為 C 語言綜合練習範本。

功能模組

  1. 新增學生資料(學號唯一性檢查、成績範圍驗證)
  2. 刪除學生(全部/按姓名/按學號)
  3. 修改成績(按學號/姓名查找後更新)
  4. 查詢學生(按學號/姓名)
  5. 顯示全部(支援 5 種排序:學號、語文、數學、英文、總分)
  6. 儲存至檔案 / 啟動自動載入

資料結構設計

/* students.h */
typedef struct st {
    unsigned long ID;
    char name[10];
    float chinese, math, english;
    double all_sub;
    float average;
    struct st *next;
} STU;

#define ASK_STU(p) do { \
    p = (STU *)malloc(sizeof(STU)); \
    if (!p) { printf("malloc failed!\n"); exit(1); } \
} while(0)

/* 函式宣告 */
STU *add_student(STU *);
STU *del_student(STU *);
void modify_student(STU *);
void search_student(STU *);
STU *display_student(STU *);
void save_student(STU *);
STU *init_student(STU *);
STU *select_sort(STU *, char);  // 通用排序
STU *search_by_nb(STU *, unsigned long);
STU *search_by_name(STU *, char *);

核心演算法實現

選擇排序(鏈表版)

/* students.c 片段 */
STU *select_sort(STU *g, char flag) {
    STU *p, *q, *t, *s, *h;
    h = (STU *)malloc(sizeof(STU));  // 虛擬頭節點
    h->next = g; p = h;

    while (p->next->next) {
        for (s = p, q = p->next; q->next; q = q->next) {
            int cmp = 0;
            switch (flag) {
                case '1': cmp = q->next->ID < s->next->ID; break;
                case '2': cmp = q->next->chinese < s->next->chinese; break;
                case '3': cmp = q->next->math < s->next->math; break;
                case '4': cmp = q->next->english < s->next->english; break;
                case '5': cmp = q->next->average < s->next->average; break;
            }
            if (cmp) s = q;
        }
        if (s != q) {  // 需交換
            t = s->next;
            s->next = t->next;
            t->next = p->next;
            p->next = t;
        }
        p = p->next;
    }
    g = h->next; free(h);
    return g;
}

新增學生(含自動排序)


STU *add_student(STU *stu_head) {
    STU *stu, *head = stu_head, *node = stu_head;
    ASK_STU(stu); stu->next = NULL;

    printf("學號: "); scanf("%lu", &stu->ID);
    while (search_by_nb(node, stu->ID)) {
        printf("學號重複,重新輸入: "); scanf("%lu", &stu->ID);
    }
    printf("姓名: "); scanf("%9s", stu->name);
    // 三科成績輸入與 0~100 驗證...
    printf("英文: "); scanf("%f", &stu->english);
    while (stu->english < 0 || stu->english > 100) { /* 重輸 */ }
    /* 數學、語文同理 */

    stu->all_sub = stu->chinese + stu->math + stu->english;
    stu->average = stu->all_sub / 3;

    if (!head) return stu;
    while (node->next) node = node->next;
    node->next = stu;
    return select_sort(head, '1');  // 預設按學號排序
}

刪除操作(三種模式)


STU *del_student(STU *stu_head) {
    int sel; STU *head = stu_head;
    printf("1:全部 2:按姓名 3:按學號 0:返回\n選擇: ");
    sel = getchar(); while (getchar()!='\n');
    if (sel == '0' || !head) return head;

    if (sel == '1') return del_all(head);  // 遞迴釋放全部

    return del_one(head, sel);  // 2 或 3
}

STU *del_one(STU *stu_head, int flag) {
    STU *node = stu_head, *head = stu_head, *pre = NULL;
    char name[10]; unsigned long ID;

    if (flag == '2') { printf("姓名: "); scanf("%9s", name); }
    else { printf("學號: "); scanf("%lu", &ID); }

    // 處理頭節點
    if ((flag == '2' && !strcmp(node->name, name)) ||
        (flag == '3' && node->ID == ID)) {
        head = node->next; free(node);
        printf("刪除成功!\n"); getchar();
        return head;
    }

    while (node) {
        int match = (flag == '2') ? !strcmp(node->name, name) : (node->ID == ID);
        if (match) {
            pre->next = node->next; free(node);
            printf("刪除成功!\n"); getchar();
            return head;
        }
        pre = node; node = node->next;
    }
    printf("未找到!\n"); getchar();
    return head;
}

檔案持久化


/* store.c */
#define FILE_NAME "students"

void save_student(STU *stu_head) {
    FILE *fp = fopen(FILE_NAME, "w+");
    STU *node = stu_head;
    while (node) {
        fprintf(fp, "%lu %s %.1f %.1f %.1f %.1lf %.1f\n",
                node->ID, node->name,
                node->chinese, node->math, node->english,
                node->all_sub, node->average);
        node = node->next;
    }
    fclose(fp);
    printf("儲存成功!\n"); getchar();
}

STU *init_student(STU *stu_head) {
    STU *head = stu_head, *node = stu_head, *new_node;
    FILE *fp = fopen(FILE_NAME, "r+");
    if (!fp) return head;

    ASK_STU(new_node); new_node->next = NULL;
    while (fscanf(fp, "%lu %s %f %f %f %lf %f",
                  &new_node->ID, new_node->name,
                  &new_node->chinese, &new_node->math, &new_node->english,
                  &new_node->all_sub, &new_node->average) == 7) {
        if (!head) head = node = new_node;
        else { while (node->next) node = node->next; node->next = new_node; }
        ASK_STU(new_node); new_node->next = NULL;
    }
    free(new_node);  // 最後多分配的一個
    fclose(fp);
    return head;
}

主程式流程


/* main.c */
int main() {
    int cmd, flag = 0;
    while (1) {
        cmd = select_menu();  // 顯示選單、讀取輸入
        hand_menu(cmd, &flag);
    }
}

void hand_menu(int cmd, int *flag) {
    static STU *stu_head = NULL;
    if (!*flag) { stu_head = init_student(stu_head); *flag = 1; }

    switch (cmd) {
        case '0': save_student(stu_head); exit(0);
        case '1': system("cls"); stu_head = add_student(stu_head); break;
        case '2': system("cls"); stu_head = del_student(stu_head); break;
        case '3': system("cls"); modify_student(stu_head); break;
        case '4': system("cls"); search_student(stu_head); break;
        case '5': system("cls"); stu_head = display_student(stu_head); break;
        case '6': system("cls"); save_student(stu_head); break;
    }
    system("cls");
}

專案總結與心得

核心能力本專案鍛鍊點
鏈表操作增、刪、改、查、排序、遞迴釋放
檔案 I/O格式化讀寫、啟動載入、退出儲存
模組化設計多檔案分離、介面抽象、靜態變數封裝
輸入健壯性範圍檢查、唯一性驗證、緩衝區保護
排序演算法鏈表選擇排序、多鍵值切換、虛擬頭節點技巧

透過此專案,從指標操作到系統架構設計都有實質突破。後續可嘗試:C++ 重構(RAII、STL)、演算法優化(合併排序 O(n log n))、GUI 介面、資料庫替代檔案存儲。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved