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

C語言鏈表實戰:學生信息管理系統(增刪改查+文件持久化)

     編輯:C 語言問答

單鏈表完整實現:學生信息管理系統

鏈表是動態數據結構基石。本文通過完整的學生管理系統(初始化、創建、遍歷、查找、刪除、文件存取)講解單鏈表核心操作。

數據結構定義

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int id;           // 學號
    char name[20];    // 姓名
    float score;      // 成績
} Student;

typedef struct Node {
    Student data;
    struct Node *next;
} Node;

Node *head = NULL;  // 全局頭指針

核心操作函數

1. 初始化

void init() { head = NULL; }

2. 創建(尾插法)

void create() {
    int n; printf("輸入學生人數: "); scanf("%d", &n);
    Node *tail = NULL;
    for (int i = 0; i < n; ++i) {
        Node *p = (Node*)malloc(sizeof(Node));
        if (!p) { perror("malloc"); exit(1); }
        printf("第%d位: 學號 姓名 成績 ", i+1);
        scanf("%d %19s %f", &p->data.id, p->data.name, &p->data.score);
        p->next = NULL;

        if (!head) head = tail = p;
        else { tail->next = p; tail = p; }
    }
}

3. 遍歷顯示

void display() {
    printf("學號\t姓名\t成績\n");
    for (Node *p = head; p; p = p->next)
        printf("%d\t%s\t%.2f\n", p->data.id, p->data.name, p->data.score);
}

4. 查找(按學號)

void search(int id) {
    for (Node *p = head; p; p = p->next)
        if (p->data.id == id) {
            printf("找到: %d %s %.2f\n", p->data.id, p->data.name, p->data.score);
            return;
        }
    printf("學號 %d 不存在\n", id);
}

5. 刪除(按學號)

void delete(int id) {
    Node *prev = NULL, *curr = head;
    while (curr && curr->data.id != id) {
        prev = curr; curr = curr->next;
    }
    if (!curr) { printf("學號 %d 不存在\n", id); return; }

    if (!prev) head = curr->next;      // 刪除頭節點
    else prev->next = curr->next;      // 刪除中間/尾節點

    free(curr);
    printf("刪除成功\n");
}

6. 文件存取(二進制)

void save_to_file(const char *filename) {
    FILE *fp = fopen(filename, "wb");
    if (!fp) { perror("save"); return; }
    for (Node *p = head; p; p = p->next)
        fwrite(&p->data, sizeof(Student), 1, fp);
    fclose(fp);
}

void load_from_file(const char *filename) {
    FILE *fp = fopen(filename, "rb");
    if (!fp) return;  // 文件不存在視為空
    Student tmp;
    Node *tail = NULL;
    while (fread(&tmp, sizeof(Student), 1, fp) == 1) {
        Node *p = (Node*)malloc(sizeof(Node));
        p->data = tmp; p->next = NULL;
        if (!head) head = tail = p;
        else { tail->next = p; tail = p; }
    }
    fclose(fp);
}

主程序框架

int main() {
    load_from_file("students.dat");
    int choice, id;
    while (1) {
        printf("\n1.創建 2.顯示 3.查找 4.刪除 5.保存 0.退出\n選擇: ");
        scanf("%d", &choice);
        switch (choice) {
            case 1: create(); break;
            case 2: display(); break;
            case 3: printf("輸入學號: "); scanf("%d", &id); search(id); break;
            case 4: printf("輸入學號: "); scanf("%d", &id); delete(id); break;
            case 5: save_to_file("students.dat"); puts("已保存"); break;
            case 0: save_to_file("students.dat"); return 0;
        }
    }
}

進階優化方向

  • 雙向鏈表:添加 prev 指針,支持反向遍歷、O(1) 尾部插入刪除。
  • 帶頭節點:哨兵節點簡化邊界判斷(頭節點不存數據)。
  • 泛型化:用 void* 數據域 + 函數指針(比較、打印、銷毀)實現通用容器。
  • 內存池:批量分配節點,減少 malloc/free 開銷,避免碎片。
  • 持久化格式:改用 JSON/CSV/SQLite,便於跨語言交互與人工閱讀。

常見錯誤避坑

  1. malloc 未檢查返回值 → 空指針解引用崩潰。
  2. 刪除節點後未 free → 內存洩漏。
  3. 遍歷時修改 next 導致鏈表斷裂或死循環。
  4. 文件讀寫未檢查 fopen/fread/fwrite 返回值。
  5. 結構體含指針(如 char *name)直接 fwrite 會寫入指針值而非字符串內容,**必須序列化**。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved