You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言单链表按birth_number删除节点功能异常问题咨询

问题排查与修复方案

原代码核心问题

  • 参数传递错误:node_delete函数传入head是值传递,函数内部修改head不会影响外部的链表头指针,导致头节点删除完全不生效。
  • 遍历逻辑缺陷:循环判断条件为temp->next != NULL,会跳过最后一个节点的匹配判断;且删除节点后直接访问已释放的temp->next属于野指针访问,会触发未定义行为。
  • 指针维护错误:previous指针未正确指向当前节点的前驱节点,删除非头节点时链表会直接断裂。
  • 内存泄漏:删除节点时仅释放了node_t结构体本身,未释放presenter和birth_number通过strdup申请的堆内存。
  • 字符串操作风险:scanf("%s", &birth_n)写法错误(数组名本身就是地址,不需要取址符);手动拼接换行符容易触发缓冲区溢出;调试版函数的字符串比较逻辑完全写反,匹配到目标反而不删除。
  • 补充:原node_load函数参数传入的file未被使用,内部硬编码读取DATABASE_FILE,属于潜在逻辑缺陷。

正确实现代码

方案1:返回新链表头(推荐,易使用)

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

node_t* node_delete(node_t *head) {
    char birth_n[14] = {0};
    // 读入目标身份证号,限制长度避免溢出
    scanf("%13s", birth_n);
    // 拼接换行符匹配fgets读入的格式,也可以选择在加载节点时提前去掉换行符
    strncat(birth_n, "\n", 1);

    node_t *curr = head;
    node_t *prev = NULL;

    while (curr != NULL) {
        if (strcmp(birth_n, curr->birth_number) == 0) {
            node_t *to_free = curr;
            // 处理头节点删除
            if (prev == NULL) {
                head = curr->next;
            } else {
                // 处理普通节点删除,衔接链表
                prev->next = curr->next;
            }
            // 移动当前指针到下一个节点
            curr = curr->next;
            // 释放节点内存
            free(to_free->presenter);
            free(to_free->birth_number);
            free(to_free);
        } else {
            // 未匹配到,前驱和当前指针都后移
            prev = curr;
            curr = curr->next;
        }
    }
    return head;
}

调用方式示例

// 原链表头为head,删除后赋值回head即可
head = node_delete(head);

方案2:用二级指针传递头节点

void node_delete(node_t **head) {
    if (head == NULL || *head == NULL) return;

    char birth_n[14] = {0};
    scanf("%13s", birth_n);
    strncat(birth_n, "\n", 1);

    node_t *curr = *head;
    node_t *prev = NULL;

    while (curr != NULL) {
        if (strcmp(birth_n, curr->birth_number) == 0) {
            node_t *to_free = curr;
            if (prev == NULL) {
                *head = curr->next;
            } else {
                prev->next = curr->next;
            }
            curr = curr->next;
            free(to_free->presenter);
            free(to_free->birth_number);
            free(to_free);
        } else {
            prev = curr;
            curr = curr->next;
        }
    }
}

调用方式示例

// 传入头指针的地址
node_delete(&head);

可选优化建议

可以在加载节点时去掉字符串末尾的换行符,避免删除时需要额外拼接换行:

// 加载presenter时去掉换行
ptr->presenter = strdup(buffer);
size_t len = strlen(ptr->presenter);
if (len > 0 && ptr->presenter[len-1] == '\n') ptr->presenter[len-1] = '\0';

// birth_number同理处理
ptr->birth_number = strdup(buffer);
len = strlen(ptr->birth_number);
if (len > 0 && ptr->birth_number[len-1] == '\n') ptr->birth_number[len-1] = '\0';

处理后删除函数中不需要再拼接\n,直接比较输入的字符串即可。

内容的提问来源于stack exchange,提问作者Erri000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 18:45:01