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

C语言链表头部结构删除后打印异常,fgets调用后代码停滞

解决链表删除学生记录及fgets停滞的问题

兄弟,我看你在C语言链表操作和输入处理上卡壳了,这俩问题其实都是新手常踩的坑,我给你逐个捋清楚:

一、头部删除记录后打印出现异常文本

这个问题大概率是头部节点删除后没有正确更新head指针,导致后续遍历链表时访问了已经被释放的内存(也就是野指针),打印出来自然是乱码或者异常文本。另外如果有重复姓氏的节点,删除逻辑没处理好也可能出问题。

给你写个靠谱的按姓氏删除的函数,你可以参考:

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

// 按姓氏删除所有匹配的学生记录
void delete_by_lastname(const char* target_lastname) {
    struct students *current = head;
    struct students *prev = NULL;

    // 先处理头部节点(可能多个匹配的头部)
    while (current != NULL && strcmp(current->lastname, target_lastname) == 0) {
        head = current->next;  // 关键!更新head为下一个有效节点
        free(current);         // 释放当前节点内存
        current = head;        // 移动到新的头部继续检查
    }

    // 处理非头部的匹配节点
    while (current != NULL) {
        // 找到第一个匹配的节点
        while (current != NULL && strcmp(current->lastname, target_lastname) != 0) {
            prev = current;
            current = current->next;
        }
        if (current == NULL) break;  // 没有更多匹配,退出循环

        // 删除当前节点
        prev->next = current->next;
        free(current);
        current = prev->next;  // 继续遍历后续节点
    }
}

这里的核心是:删除头部节点时必须更新head指针,不然原来的head指向的内存已经被释放,后续打印时访问这个野指针就会出现异常。另外要记得释放节点内存,避免内存泄漏。

打印链表的时候也要注意,必须从head开始遍历,直到current == NULL为止,别越界:

void print_students() {
    struct students *current = head;
    while (current != NULL) {
        printf("Name: %s %s, Score: %.2f, Zip: %d\n", 
               current->firstname, current->lastname, current->score, current->zip);
        current = current->next;
    }
}

二、调用fgets后代码停滞

这个问题几乎都是输入缓冲区残留的换行符搞的鬼!比如你之前用scanf读取score或者zip这类数值时,用户输入完按回车,scanf只会读取数值,而回车(\n)会留在输入缓冲区里。当你后续调用fgets时,它会直接读取这个换行符,导致看似“停滞”(其实是fgets已经读完了空行,可能你的逻辑没处理这种情况,就卡住了)。

解决方法很简单:在调用fgets之前,先清空输入缓冲区的残留字符:

// 安全清空输入缓冲区
void clear_input_buffer() {
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
}

然后在调用fgets前调用这个函数:

// 比如在add函数里读取名字前
clear_input_buffer();
printf("Enter first name: ");
fgets(new_node->firstname, sizeof(new_node->firstname), stdin);

// 别忘了去掉fgets读取到的换行符
size_t first_len = strlen(new_node->firstname);
if (first_len > 0 && new_node->firstname[first_len - 1] == '\n') {
    new_node->firstname[first_len - 1] = '\0';
}

// 读取姓氏同理
clear_input_buffer();
printf("Enter last name: ");
fgets(new_node->lastname, sizeof(new_node->lastname), stdin);
size_t last_len = strlen(new_node->lastname);
if (last_len > 0 && new_node->lastname[last_len - 1] == '\n') {
    new_node->lastname[last_len - 1] = '\0';
}

另外要注意,fgets的第二个参数必须是数组的大小(比如sizeof(new_node->firstname)),这样能避免缓冲区溢出。

最后再提两个新手容易忘的点:

  • 每次malloc后一定要检查是否成功:if (new_node == NULL) { printf("Memory allocation failed!\n"); return; }
  • 程序结束前要遍历整个链表,释放所有节点的内存,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:19:55