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

C语言单链表删除首节点函数误删第二个节点问题排查求助

问题现象

C语言实现单链表删除首节点功能时,执行删除逻辑后实际被删除的是第二个节点,而非预期的首节点。


相关代码片段

1. 节点结构体定义

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
 /* Node structure */
typedef struct node {
    int data;
    struct node *next;
} Node;

2. 链表创建函数

/* Create the linked list */
void create_list(Node *head) {
    char check;
    int i=1, num;
    char * temp;
    
    printf("Input data for node 1: ");
    scanf("%d", &num);
    head->data = num;
    
    printf("\nEnter more <y>es/<n>o ? ");
    scanf(" %c", &check);
    
    while(check=='y') {
        head -> next = (Node *) malloc(sizeof(Node));
        head = head->next;
    
        printf("\nInput data for node %d: ",i+1);
        scanf("%d", &head->data);
        i++;
        head->next = NULL;
        printf("\nEnter more <y>es/<n>o ? ");
        if (scanf(" %c", &check)!= 1) {
            printf(" Error: Invalid Input \n");
            scanf(" %s", &temp); /* Clear input buffer */
            continue;   
    }
}
}

3. 存在逻辑错误的首节点删除函数

/* Delete first location*/
void delete_first(Node *head) {
    Node *prev_node;

    prev_node = head;//assign the prev pointer to beginning of the list
    head = head->next;//shift the node to next
    
    if(head == NULL)//condition for no elements in list
        printf("\n The List is empty ");
    else { //logic for deletion
        prev_node->next = head->next;
        free(head); //delete the node
}
}

4. 主函数

int main() {
Node *head, start;
    
start.next = NULL;
head = &start;
    
create_list(head);

head = &start;
delete_first(head);
}

错误根因排查

问题核心出在delete_first函数的逻辑错误,和链表创建函数无关,具体问题点如下:

  • 删除逻辑完全写反:函数内先将prev_node指向真正的首节点(传入的原始head),紧接着把局部变量head移动到第二个节点位置。后续执行prev_node->next = head->next时,实际是把首节点的next指针直接指向第三个节点,再调用free(head)释放的是已经指向第二个节点的指针,最终表现为第二个节点被删除,首节点残留。
  • 空判断位置错误:逻辑上先移动head指针再判断空,如果链表仅存1个节点,head = head->next会得到NULL,后续访问head->next会直接触发空指针崩溃。
  • 参数传递方式错误:C语言函数参数为值传递,delete_first中修改的是函数内的局部head副本,函数执行结束后主函数的head指针仍指向旧的首节点地址,就算删除逻辑正确,外部头指针也不会同步更新。
  • 链表创建函数存在隐藏内存错误:定义的char *temp是未初始化的野指针,输入非法时执行scanf(" %s", &temp)会向随机内存地址写入数据,可能触发程序崩溃。

修复方案

1. 修正首节点删除逻辑

需要用二级指针传入头节点地址,才能真正修改外部的头指针,同时调整删除逻辑顺序:

/* Delete first location*/
void delete_first(Node **head) {
    // 先判断链表是否为空,不要先移动指针
    if(*head == NULL) {
        printf("\n The List is empty ");
        return;
    }
    Node *to_delete = *head; // 记录要删除的首节点地址
    *head = (*head)->next;   // 把头指针移动到下一个节点
    free(to_delete);         // 释放原来的首节点
}

2. 修正主函数调用方式

传入头指针的地址即可:

int main() {
Node *head, start;
    
start.next = NULL;
head = &start;
    
create_list(head);

head = &start;
delete_first(&head); // 传入头指针的地址
}

3. 修复创建函数的野指针问题

将野指针改为固定长度的字符数组用于清空输入缓存:

/* Create the linked list */
void create_list(Node *head) {
    char check;
    int i=1, num;
    char temp[32]; // 替换原来的野指针
    
    printf("Input data for node 1: ");
    scanf("%d", &num);
    head->data = num;
    head->next = NULL; // 补全首节点的next初始化
    
    printf("\nEnter more <y>es/<n>o ? ");
    scanf(" %c", &check);
    
    while(check=='y') {
        head -> next = (Node *) malloc(sizeof(Node));
        head = head->next;
    
        printf("\nInput data for node %d: ",i+1);
        scanf("%d", &head->data);
        i++;
        head->next = NULL;
        printf("\nEnter more <y>es/<n>o ? ");
        if (scanf(" %c", &check)!= 1) {
            printf(" Error: Invalid Input \n");
            scanf("%s", temp); /* 安全清空输入缓冲区 */
            check = 'n';
    }
}
}

边界提示:当前代码的首节点是栈上分配的start变量,如果链表只有这一个节点,free栈上的内存会触发非法访问,生产环境实现链表建议头节点也用堆分配,或者单独处理首节点是栈变量的边界场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 22:09:23