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

C 語言單鏈表通訊錄實作:結構體設計、查找、插入、記憶體管理完整指南

     編輯:C 語言問答

需求分析

  • 記錄:姓名 (字串)、電話 (字串)。
  • 功能:建立、查找指定姓名、指定節點前插入 (不存在則尾插)。

資料結構設計


#include 
#include 
#include 

typedef struct Node {
    char name[32];
    char phone[16];
    struct Node *next;
} Node;

// 建立節點
Node* create_node(const char *name, const char *phone) {
    Node *n = malloc(sizeof(Node));
    if (!n) { perror("malloc"); exit(EXIT_FAILURE); }
    strncpy(n->name, name, sizeof(n->name)-1);
    n->name[sizeof(n->name)-1] = '\0';
    strncpy(n->phone, phone, sizeof(n->phone)-1);
    n->phone[sizeof(n->phone)-1] = '\0';
    n->next = NULL;
    return n;
}

核心操作實作

1. 尾插建立鏈表 (保持輸入順序)


Node* build_list(void) {
    Node *head = NULL, *tail = NULL;
    char name[32], phone[16];
    printf("輸入姓名 電話 (空行結束):\n");
    while (scanf("%31s %15s", name, phone) == 2) {
        Node *n = create_node(name, phone);
        if (!head) head = tail = n;
        else { tail->next = n; tail = n; }
    }
    return head;
}

2. 查找姓名 (返回節點指標,未找到返回 NULL)


Node* find_by_name(Node *head, const char *name) {
    for (Node *p = head; p; p = p->next)
        if (strcmp(p->name, name) == 0)
            return p;
    return NULL;
}

3. 指定節點前插入 (不存在則尾插)


void insert_before(Node **head_ref, const char *target_name, Node *new_node) {
    Node *prev = NULL, *curr = *head_ref;
    while (curr && strcmp(curr->name, target_name) != 0) {
        prev = curr;
        curr = curr->next;
    }
    if (!curr) { // 未找到 → 尾插
        if (!*head_ref) *head_ref = new_node;
        else {
            Node *tail = *head_ref;
            while (tail->next) tail = tail->next;
            tail->next = new_node;
        }
    } else if (!prev) { // 插在頭節點前 → 新頭
        new_node->next = *head_ref;
        *head_ref = new_node;
    } else { // 一般情況
        prev->next = new_node;
        new_node->next = curr;
    }
}

4. 釋放整個鏈表 (防洩漏)


void free_list(Node *head) {
    while (head) {
        Node *tmp = head;
        head = head->next;
        free(tmp);
    }
}

主程式整合


int main(void) {
    Node *contacts = build_list();

    // 示範查找
    char query[32];
    printf("查找姓名: ");
    if (scanf("%31s", query) == 1) {
        Node *found = find_by_name(contacts, query);
        if (found) printf("找到: %s %s\n", found->name, found->phone);
        else printf("未找到\n");
    }

    // 示範插入
    char target[32], new_name[32], new_phone[16];
    printf("插入於哪位之前 (姓名): ");
    if (scanf("%31s", target) == 1) {
        printf("新聯繫人 姓名 電話: ");
        if (scanf("%31s %15s", new_name, new_phone) == 2) {
            Node *n = create_node(new_name, new_phone);
            insert_before(&contacts, target, n);
        }
    }

    // 列印驗證
    printf("\n通訊錄內容:\n");
    for (Node *p = contacts; p; p = p->next)
        printf("%s\t%s\n", p->name, p->phone);

    free_list(contacts);
    return 0;
}

關鍵細節總結

環節關鍵點
字串複製strncpy + 手動加 \0,防溢位
輸入安全scanf("%31s", buf) 限制寬度 = 陣列大小-1
插入邊界頭插、尾插、中間插、空表、目標不存在 全覆蓋
雙重指標Node **head_ref 允許修改頭指標 (頭插時)
記憶體釋放主程式結束前 free_list,Valgrind 0 leaks

進階擴充建議

  • 改用 **雙向鏈表** (含 prev) 使刪除/反向遍歷 O(1)。
  • 引入 **雜湊表** (姓名 → 節點) 使查找 O(1)。
  • 持久化:fwrite 結構體陣列或序列化 JSON/CSV 存檔。
  • 介面:ncurses TUI / 簡易 HTTP 伺服器 (cJSON + libmicrohttpd)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved