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

CS50 PSET5:简易字典实现出现Segmentation core dumped错误

哈希表实现内存错误排查

你的代码一共存在5处会触发内存错误/逻辑错误的问题,逐一列示如下:

  • fscanf读取目标无合法内存:load函数中定义的char *word = NULL是空指针,直接传入fscanf作为字符串写入地址会触发非法内存写入,直接崩溃。应将其定义为长度匹配的字符数组:char word[LENGTH + 1];,栈上分配的数组可以直接被fscanf写入。
  • 文件读取逻辑死循环:仅在进入循环前调用了一次fscanf,循环内部没有再次读取文件内容的逻辑,word_count永远不会变为EOF,会无限执行malloc直到内存耗尽。另外你对fscanf返回值理解有误:它返回的是本次成功读取的字段数量,不是累计单词总数,需要在每次处理完当前单词后,再次调用fscanf读取下一个单词,用返回值判断是否到达文件尾。
  • 链表插入逻辑断链:插入非空桶时使用了局部变量head作为新节点的next指向目标,但head仅在第一次插入空桶时被赋值,后续切换到其他哈希桶插入时,head存储的是旧桶的链表地址,会造成链表断裂、节点丢失。正确的头插逻辑不需要额外的head变量,直接让新节点的next指向当前桶的头指针table[node_index],再更新桶头指针为新节点即可,空桶场景下该逻辑同样适用,不需要单独判断。
  • 内存释放逻辑空指针访问:unload函数中,cursor指针移动到下一个节点后,执行temp = cursor->next时,若cursor已经为NULL(即遍历到链表尾),会直接访问空指针触发崩溃。正确的遍历释放逻辑为:临时指针存当前节点地址,cursor后移一位,释放临时指针指向的节点,循环直到cursor为NULL。
  • 资源泄漏:打开的文件指针没有调用fclose关闭,会造成文件句柄泄漏;malloc失败返回错误前也需要关闭已打开的文件,避免资源泄漏。另外你原代码里的word_count变量存储的是fscanf的返回值,不是字典总单词数,需要每插入一个节点就累加计数,或者加载完成后遍历链表统计。

修正后的核心代码

// Implements a dictionary's functionality
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include "dictionary.h"

// 字典单词总数
int word_count = 0;

// 哈希表节点结构
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
}
node;

// 哈希桶数量
const unsigned int N = 26;

// 哈希表
node *table[N];

// 初始化哈希表,所有指针置空
void init_table()
{
    for (int i = 0; i < N; i++)
    {
        table[i] = NULL;
    }
}

// 检查单词是否存在于字典中
bool check(const char *word)
{
    unsigned int node_index = hash(word);
    node *cursor = table[node_index];
    while (cursor != NULL)
    {
        if (strcasecmp(cursor->word, word) == 0)
        {
            return true;
        }
        cursor = cursor->next;
    }
    return false;
}

// 简易哈希函数
unsigned int hash(const char *word)
{
    return ((toupper(word[0]) - 'A') % N);
}

// 加载字典到内存
bool load(const char *dictionary)
{
    char word[LENGTH + 1];
    FILE *file = fopen(dictionary, "r");
    if (file == NULL)
    {
        return false;
    }

    init_table();
    word_count = 0;
    // 读取第一个单词
    int read_ret = fscanf(file, "%s", word);

    while (read_ret != EOF)
    {
        node *n = malloc(sizeof(node));
        if (n == NULL)
        {
            fclose(file);
            return false;
        }

        strcpy(n->word, word);
        unsigned int node_index = hash(n->word);
        // 统一头插逻辑,无需判断空桶
        n->next = table[node_index];
        table[node_index] = n;
        word_count++;

        // 读取下一个单词
        read_ret = fscanf(file, "%s", word);
    }

    fclose(file);
    return true;
}

// 释放哈希表内存
bool unload(void)
{
    for (int i = 0; i < N; i++)
    {
        node *cursor = table[i];
        while (cursor != NULL)
        {
            node *temp = cursor;
            cursor = cursor->next;
            free(temp);
        }
        table[i] = NULL;
    }
    return true;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 10:03:43