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

C語言實現通訊錄管理系統:鏈表版完整代碼詳解與擴展指南

     編輯:C 語言問答

項目概覽

基於單向鏈表實現的控制台通訊錄系統,功能涵蓋:增刪改查、分類篩選、自動排序、撥號模擬、持久化存儲。代碼採用 C++ 風格 (引用、new/delete、iostream) 但邏輯純 C 風格,適合 C 語言學習者參考數據結構落地。

核心數據結構設計

typedef struct {
    char name[25];      // 姓名
    char number[50];    // 電話
    int  id;            // 序號 (自動維護)
    char category;      // 分類 A/B/C
    char email[50];     // 郵箱
} Contact;

typedef struct Node {
    Contact data;
    struct Node *next;
} Node, *LinkList;      // LinkList 為指向頭節點的指針

關鍵模塊功能解析

1. 內存管理與初始化

LinkList init_list() {
    LinkList L = (LinkList)malloc(sizeof(Node));  // 頭節點不存數據
    L->next = NULL;
    return L;
}

void free_list(LinkList L) {
    Node *p = L->next, *tmp;
    while (p) { tmp = p; p = p->next; free(tmp); }
    free(L);
}

2. 尾插法添加聯系人 (含去重、分類、持久化鉤子)


int add_contact(LinkList L) {
    if (count_contacts(L) >= 15) { puts("通訊錄已滿"); return 0; }
    Node *p = (Node*)malloc(sizeof(Node));
    p->next = NULL;
    
    printf("姓名: "); scanf("%24s", p->data.name);
    printf("電話: "); scanf("%49s", p->data.number);
    // 去重檢查
    if (find_by_name_or_number(L, p->data.name, p->data.number)) {
        puts("聯系人已存在"); free(p); return 0;
    }
    printf("分類(A/B/C): "); scanf(" %c", &p->data.category);
    printf("郵箱: "); scanf("%49s", p->data.email);
    
    // 尾插
    Node *tail = L;
    while (tail->next) tail = tail->next;
    tail->next = p;
    renumber(L);  // 重新分配序號
    return 1;
}

3. 刪除聯系人 (按姓名、釋放內存、重排序號)


int delete_contact(LinkList L) {
    char name[25];
    printf("刪除姓名: "); scanf("%24s", name);
    Node *prev = L, *cur = L->next;
    while (cur && strcmp(cur->data.name, name) != 0) {
        prev = cur; cur = cur->next;
    }
    if (!cur) { puts("未找到"); return 0; }
    prev->next = cur->next;
    free(cur);
    renumber(L);
    puts("刪除成功"); return 1;
}

4. 多模式查詢

  • 遍歷顯示:打印所有聯系人姓名+序號,再輸入姓名查看詳情
  • 分類篩選:輸入 A/B/C,遍歷匹配 category 輸出
  • 姓名/電話精確查找:strcmp 匹配

5. 自動撥號模擬 (Windows API)


void simulate_dial(const char *number) {
    system("cls");
    for (int i = 0; number[i]; ++i) {
        putchar('\a');          // 蜂鳴器
        putchar(number[i]);     // 逐字符輸出
        fflush(stdout);
        Sleep(300);             // windows.h, 300ms 間隔
    }
    putchar('\n');
}

6. 文件持久化 (文本格式 CSV)


void save_to_file(LinkList L, const char *filename) {
    FILE *fp = fopen(filename, "w");
    for (Node *p = L->next; p; p = p->next)
        fprintf(fp, "%s,%s,%c,%s\n", p->data.name, p->data.number, p->data.category, p->data.email);
    fclose(fp);
}

void load_from_file(LinkList L, const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (!fp) return;
    char line[200];
    while (fgets(line, sizeof(line), fp)) {
        Node *p = (Node*)malloc(sizeof(Node));
        p->next = NULL;
        sscanf(line, "%24[^,],%49[^,],%c,%49[^\n]", p->data.name, p->data.number, &p->data.category, p->data.email);
        // 尾插...
    }
    fclose(fp);
    renumber(L);
}

主程序架構


int main(void) {
    LinkList L = init_list();
    load_from_file(L, "contacts.csv");
    
    int choice;
    while (1) {
        print_menu();
        scanf("%d", &choice);
        switch (choice) {
            case 1: list_all(L); break;
            case 2: query_by_category(L); break;
            case 3: delete_contact(L); break;
            case 4: add_contact(L); break;
            case 5: simulate_dial_by_name(L); break;
            case 0: save_to_file(L, "contacts.csv"); free_list(L); return 0;
            default: puts("無效選項");
        }
    }
}

代碼規範與安全性增強建議

問題原代碼改進方案
輸入緩衝區溢出scanf("%s", name)scanf("%24s", name) 限制寬度
混合 C/C++ 風格new/delete, iostream, malloc/free 混用純 C: malloc/free, stdio.h; 或純 C++: new/delete, iostream, string, vector
fflush(stdin) 未定義行為清理輸入緩衝區int c; while((c=getchar())!='\n' && c!=EOF);
無錯誤碼返回關鍵函數無返回值關鍵操作返回 int (0 失敗/1 成功),主循環檢查
硬編碼限制最大 15 聯系人配置常量 MAX_CONTACTS,動態分配無上限
跨平台兼容Sleep, system("cls"), \\a抽象平台層,或用 ANSI 轉義序列 \033[2J\033[H 清屏

進階擴展方向

  1. 數據結構優化:雙向鏈表 (便於反向遍歷)、哈希表 (O(1) 查找)、Trie 樹 (前綴匹配/自動補全)。
  2. 持久化升級:SQLite 嵌入式數據庫 (ACID、并發、SQL 查詢)、二進制序列化 (Protocol Buffers/FlatBuffers)。
  3. 界面升級:ncurses (終端 TUI)、GTK/Qt (GUI)、WebAssembly + HTML/CSS (跨平台 Web 版)。
  4. 網絡化:Client-Server 架構、REST API、數據同步、多端登錄。
  5. 測試驅動:Unity/CMock 單元測試、Valgrind/ASan 內存檢測、CI/CD (GitHub Actions) 自動化。

總結

這個通訊錄項目雖屬教學級,但完整覆蓋了 動態內存管理、鏈表操作、字符串處理、文件 I/O、模塊化設計、用戶交互、平台 API 調用 等 C 語言核心工程技能。建議學習者:

  1. 先完整跑通原代碼,觀察每個功能行為
  2. 重寫為純 C99 風格 (去除 C++ 特性),修復上述安全性問題
  3. 添加單元測試 (如測試添加/刪除/查找/保存/加載)
  4. 嘗試重構為雙向鏈表 + SQLite 持久化 版本
  5. 最終產出一個有 README、有 Makefile/CMakeLists.txt、有測試、無 Valgrind 錯誤 的 GitHub 倉庫

這就是從「跟著敲代碼」到「獨立交付項目」的關鍵躍遷。

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