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

同一段C链表代码在VS与cs50.dev运行差异:段错误原因咨询

链表代码在cs50.dev出现段错误的原因及修复方案

核心段错误原因

  • 空指针解引用(直接触发错误):add函数开头的判断if (strcmp(first->name, "\0") == 0)完全错误。程序启动时全局变量first初始化为NULL,第一次调用add时直接访问first->name属于空指针解引用,这在cs50.dev使用的GCC编译器环境下会直接触发段错误。Visual Studio可能因内存布局特性,未初始化的指针恰好指向一段可读的全0内存,侥幸没触发错误,但这属于未定义行为。
  • 语法错误:头文件下方有一个多余的s字符,会导致编译失败,必须删除。

其他潜在Bug(需修复避免后续问题)

  • print函数未处理空链表:如果链表为空(比如调用delete删完所有节点后调用print),index = first为NULL,访问index->next会触发段错误。
  • delete函数循环条件逻辑反转:while (index != NULL && !(strcmp(index->name, name)))的逻辑是“找到目标节点时继续遍历”,这会跳过目标节点,导致无法正确定位要删除的节点。正确逻辑应该是“未找到目标节点时继续遍历”。
  • 删除头节点后未更新last:若删除头节点后链表为空,last会指向已释放的内存,成为野指针。

修复后的完整代码

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

int add(char *name, int pow, char class);
int delete(char *name);
int print();

typedef struct addhero
{
    char name[50];
    int pow;
    char class;
    struct addhero *next;
} addhero;
addhero *first = NULL;
addhero *last = NULL;

int main()
{
    char yn = ' ';
    while (1){
        char hn[50];
        int hp = 0;
        char hc = ' ';
        printf("Enter hero name: ");
        scanf(" %s", hn);
        printf("Enter hero power: ");
        scanf(" %d", &hp);
        printf("Enter hero class: ");
        scanf(" %c", &hc);
        add(hn, hp, hc);
        printf("Keep going to add? (Y/N): ");
        scanf(" %c", &yn);
        if (islower(yn)) yn = toupper(yn);
        if (yn == 'N')
            break;
    }
    print();
}

int add(char *name, int pow, char class)
{
    // 修复:用first == NULL判断链表是否为空
    if (first == NULL){
        addhero *new = malloc(sizeof(addhero)); // C中无需强制转换malloc返回值
        strcpy(new->name, name);
        new->pow = pow;
        new->class = class;
        new->next = NULL;

        first = last = new;
    }
    else{
        addhero *new = malloc(sizeof(addhero));
        strcpy(new->name, name);
        new->pow = pow;
        new->class = class;
        new->next = NULL;

        last->next = new;
        last = new;
    }
    return 0;
}

int delete(char *name)
{
    addhero *prev = NULL;
    addhero *index = first;
    if (first == NULL){
        printf("There is no hero now.\n");
        return 0;
    }
    // 删除头节点
    if (strcmp(first->name, name) == 0){
        addhero *temp = first;
        first = first->next;
        // 修复:删完头节点后链表为空时更新last
        if (first == NULL)
            last = NULL;
        free(temp);
        return 0;
    }
    // 修复循环条件:未找到目标时继续遍历
    while (index != NULL && strcmp(index->name, name) != 0){
        prev = index;
        index = index->next;
    }
    if (index == NULL){
        printf("There is no hero in this name.\n");
        return 0;
    }
    prev->next = index->next;
    // 删除尾节点时更新last
    if (index == last){
        last = prev;
    }
    free(index);
    return 0;
}

int print()
{
    // 修复:处理空链表情况
    if (first == NULL){
        printf("\n-> ╠══ Your Heroes ══╬\n");
        printf("-----------------------\n");
        printf("No heroes in the list.\n");
        printf("-----------------------\n");
        return 0;
    }

    printf("\n-> ╠══ Your Heroes ══╬\n");
    printf("-----------------------\n");
    addhero *index = first;
    // 修复循环逻辑:遍历所有节点,无需单独处理last
    while (index != NULL)
    {
        printf("-> Hero: %s ══ %d | %c\n", index->name, index->pow, index->class);
        index = index->next;
    }
    printf("-----------------------\n");
    return 0;
}

额外说明

  • C语言中malloc的返回值无需强制转换为结构体指针,强制转换反而可能隐藏潜在的编译错误。
  • print函数简化了遍历逻辑,直接遍历所有节点直到NULL,无需单独处理尾节点,代码更简洁可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 04:12:02