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

C 語言專案實戰:教師資訊管理系統 (動態記憶體、檔案 IO、模組化設計)

     編輯:關於C

專案概覽

本專案實作一個**教師資訊管理系統**,功能涵蓋:新增、顯示、查詢、修改、刪除、檔案存取 (文字/二進位)、動態記憶體擴容。展示 C 語言結構體、指標、動態陣列、檔案操作、模組化設計的綜合應用。

核心資料結構

#define SIZE sizeof(Teacher)
#define INIT_CAPACITY 10

typedef struct {
    char number[20];   // 工號
    char name[20];     // 姓名
    char sex[10];      // 性別: "man"/"woman"
    char addr[50];     // 地址
    char married[10];  // 婚姻: "Yes"/"No"
} Teacher;

Teacher *tea = NULL;   // 動態陣列基址
int numtea = 0;        // 目前教師數
int lens = 0;          // 目前配置容量

功能模組詳解

1. 動態新增教師 (支援擴容)

void add_tea(Teacher **tea) {  // 傳二級指標,可修改主程式 tea 基址
    char str[5];
    int num, i = 0;

    if (numtea != 0) {
        printf("覆蓋現有記錄? (y/n): ");
        fgets(str, sizeof(str), stdin);
        if (str[0] != 'y' && str[0] != 'Y') i = numtea;  // 續接模式
    }

    printf("輸入新增教師數: ");
    scanf("%d", &num);
    while (getchar() != '\n');  // 清緩衝區

    if (i == 0) numtea = num; else numtea += num;

    // 容量檢查與擴容 (realloc)
    if (numtea > lens) {
        lens += 10;
        Teacher *tmp = realloc(*tea, lens * SIZE);
        if (!tmp) { perror("記憶體不足"); exit(1); }
        *tea = tmp;  // 更新基址
    }

    for (; i < numtea; i++) {
        printf("教師 %d 資訊:\n", i+1);
        printf("工號: "); fgets((*tea)[i].number, sizeof((*tea)[i].number), stdin); (*tea)[i].number[strcspn((*tea)[i].number, "\n")] = 0;
        printf("姓名: "); fgets((*tea)[i].name, sizeof((*tea)[i].name), stdin); (*tea)[i].name[strcspn((*tea)[i].name, "\n")] = 0;
        printf("性別 (0=man/1=woman): "); fgets(str, sizeof(str), stdin);
        strcpy((*tea)[i].sex, (str[0]=='0') ? "man" : "woman");
        printf("地址: "); fgets((*tea)[i].addr, sizeof((*tea)[i].addr), stdin); (*tea)[i].addr[strcspn((*tea)[i].addr, "\n")] = 0;
        printf("婚姻 (0=No/1=Yes): "); fgets(str, sizeof(str), stdin);
        strcpy((*tea)[i].married, (str[0]=='0') ? "No" : "Yes");
    }
    display_tea(*tea, 0, numtea-1);
}

關鍵點:

  • 參數 Teacher **tea:realloc 可能移動記憶體,必須透過二級指標更新主程式指標
  • realloc 安全模式:用暫存指標接收,檢查 NULL 再賦值,避免記憶體洩漏
  • 輸入用 fgets + 去換行,比 gets (已移除 C11) / scanf 安全

2. 顯示教師資訊

void display_tea(Teacher *tea, int n1, int n2) {
    if (numtea == 0) {
        puts("無資料");
        return;
    }
    for (int i = n1; i <= n2; i++) {
        printf("工號:%-10s 姓名:%-10s 性別:%-6s 地址:%-20s 婚姻:%s\n",
               tea[i].number, tea[i].name, tea[i].sex, tea[i].addr, tea[i].married);
    }
}

3. 查詢教師 (多欄位模糊/精確)

int find_tea(Teacher *tea) {
    if (numtea == 0) return -1;
    char str[20], field[10];
    printf("查詢欄位 (1.工號 2.姓名 3.地址): ");
    fgets(field, sizeof(field), stdin);
    printf("輸入關鍵字: ");
    fgets(str, sizeof(str), stdin);
    str[strcspn(str, "\n")] = 0;

    for (int i = 0; i < numtea; i++) {
        int match = 0;
        if (field[0]=='1') match = strcmp(tea[i].number, str) == 0;
        else if (field[0]=='2') match = strcmp(tea[i].name, str) == 0;
        else if (field[0]=='3') match = strcmp(tea[i].addr, str) == 0;
        if (match) { display_tea(tea, i, i); return i; }
    }
    puts("查無資料");
    return -1;
}

4. 修改/刪除教師

void adjust_tea(Teacher *tea) {
    char str[5];
    while (1) {
        int idx = find_tea(tea);
        if (idx < 0) return;
        printf("刪除? (y/n): "); fgets(str, sizeof(str), stdin);
        if (str[0]=='y' || str[0]=='Y') {
            delete_tea(tea, idx);
            continue;
        }
        printf("修改? (y/n): "); fgets(str, sizeof(str), stdin);
        if (str[0]=='y' || str[0]=='Y') {
            // 重新輸入該筆資料 (略,同 add_tea 邏輯)
        }
        printf("繼續調整? (y/n): "); fgets(str, sizeof(str), stdin);
        if (str[0]!='y' && str[0]!='Y') break;
    }
}

void delete_tea(Teacher *tea, int idx) {
    for (int i = idx; i < numtea - 1; i++) tea[i] = tea[i+1];  // 結構體整體賦值移動
    numtea--;
    puts("刪除成功");
}

5. 檔案存取 (文字模式 + 二進位模式)

// 寫入文字檔 (可讀、可攜)
int write_txt(Teacher *tea) {
    char filename[50];
    printf("檔名: "); fgets(filename, sizeof(filename), stdin);
    filename[strcspn(filename, "\n")] = 0;

    FILE *fp = fopen(filename, "w");
    if (!fp) { perror("開檔失敗"); return -1; }
    fprintf(fp, "%d\n", numtea);
    for (int i = 0; i < numtea; i++) {
        fprintf(fp, "%s %s %s %s %s\n",
                tea[i].number, tea[i].name, tea[i].sex, tea[i].addr, tea[i].married);
    }
    fclose(fp);
    puts("儲存成功");
    return 0;
}

// 讀取文字檔
int read_txt(Teacher **tea) {
    char filename[50], str[5];
    printf("檔名: "); fgets(filename, sizeof(filename), stdin);
    filename[strcspn(filename, "\n")] = 0;

    if (numtea != 0) {
        puts("現有資料未存檔,先存檔? (y/n)");
        fgets(str, sizeof(str), stdin);
        if (str[0]=='y' || str[0]=='Y') write_txt(*tea);
    }

    FILE *fp = fopen(filename, "r");
    if (!fp) { perror("開檔失敗"); return -1; }

    int count;
    fscanf(fp, "%d\n", &count);
    if (count > lens) {
        lens = count + 10;
        Teacher *tmp = realloc(*tea, lens * SIZE);
        if (!tmp) { fclose(fp); return -1; }
        *tea = tmp;
    }
    for (int i = 0; i < count; i++) {
        fscanf(fp, "%s %s %s %s %s\n",
               (*tea)[i].number, (*tea)[i].name, (*tea)[i].sex, (*tea)[i].addr, (*tea)[i].married);
    }
    numtea = count;
    fclose(fp);
    puts("讀取成功");
    return 0;
}

主選單與程式進入點

void menu() {
    puts("\n=== 教師資訊管理系統 ===");
    puts("1. 新增教師");
    puts("2. 顯示全部");
    puts("3. 查詢教師");
    puts("4. 修改/刪除");
    puts("5. 存檔 (文字)");
    puts("6. 讀檔 (文字)");
    puts("0. 離開");
    printf("選擇: ");
}

int main() {
    tea = malloc(INIT_CAPACITY * SIZE);
    lens = INIT_CAPACITY;
    if (!tea) return 1;

    int choice;
    while (1) {
        menu();
        scanf("%d", &choice);
        while (getchar() != '\n');  // 清緩衝區
        switch (choice) {
            case 1: add_tea(&tea); break;
            case 2: display_tea(tea, 0, numtea-1); break;
            case 3: find_tea(tea); break;
            case 4: adjust_tea(tea); break;
            case 5: write_txt(tea); break;
            case 6: read_txt(&tea); break;
            case 0: free(tea); puts("再見"); return 0;
            default: puts("無效選項");
        }
    }
}

專案亮點總結

技術點應用處關鍵收穫
動態陣列 + realloc教師陣列擴容二級指標更新基址、realloc 安全模式
結構體陣列操作增刪改查、排序整體賦值移動、字串欄位處理
安全字串輸入所有輸入fgets + 去換行、避免 gets/scanf 緩衝區殘留
檔案 IO 兩種模式文字/二進位fprintf/fscanf 可讀性;fwrite/fread 效能

擴充方向

  • 引入 qsort 實現多欄位排序
  • 改用 SQLite 做持久化,支援複雜查詢
  • 加入單元測試 (Unity/CMock)
  • 模組化拆分:teacher.h/c, storage.h/c, ui.h/c
  • 支援 UTF-8 中文路徑與內容 (Windows 需 _wfopen / SetConsoleOutputCP(65001))

此專案展示了 C 語言處理中型資料管理應用的完整骨架,是從「寫語法練習」邁向「寫工程級程式」的優秀範例。

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