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

如何调试CS50 Speller代码中的Segmentation Fault (Core Dumped)错误?

CS50 Pset5 Speller 段错误问题排查

我知道让大家帮忙调代码有点唐突,但实在是绞尽脑汁都搞不定——我的橡皮鸭都躲到书桌外去了。言归正传,我在CS50的pset5项目Speller里碰到了麻烦:代码编译没问题,但运行时总是出现段错误。更奇怪的是用CS50官方的check50检测居然全过,就像代码完全正常一样,这让我彻底懵了。我试过用调试器,也检查了所有能想到的内存操作NULL返回情况,但还是找不到问题根源。

以下是我的代码:

// 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"

// Represents a node in a hash table
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
} node;

// Choose number of buckets in hash table
const unsigned int N = 150001; //Bigger than word count for enough buckets (Not concerned about memory space)

// Hash table
node *table[N];

// Variable with the amount of words in the dictionary
int count = 0;

// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    // hash word for value in table
    int hash_value = hash(word);

    // access list at hash value and compare words (strcompare)
    node *p = table[hash_value];

    // loop to end of linked list
    while (p != NULL)
    {
        if (strcasecmp(word, p->word) == 0)
        {
            return true;
        }
        p = p->next;
    }
    return false;
}

// Hashes word to a number
/*CREDIT: JR(joseph28robinson) from website medium.com for helping with HASH TABLE theory*/
unsigned int hash(const char *word)
{
    long x = 0;

    // Improve this hash function
    for (int i = 0, n = strlen(word); i < n; i++)
    {
        // I am unsure if the subtraction of 'A' is needed
        x += toupper(word[i]);
    }

    return x % N;
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    // Open file
    FILE *dict_file = fopen(dictionary, "r");
    if (dictionary == NULL)
    {
        // Could not open dictionary
        return false;
    }

    // Buffer for reading file
    char new_word[LENGTH + 1];

    // Scan file for every word and create a new node for each one
    // (NOT SURE WHY ==1 instead of != EOF /*CREDIT: Creig Estey comment from stackoverflow.com*/)
    while (fscanf(dict_file, "%s", new_word) == 1)
    {
        // Get word's hash value
        int hash_value = hash(new_word);

        // Malloc space for node
        node *p = malloc(sizeof(node));
        if (p == NULL)
        {
            return false;
        }

        // Fill in new node's variables
        strcpy(p->word, new_word);

        // TODO: Check for available space in hash's table hash_value node or create linked list
        if (table[hash_value] == NULL)
        {
            // First item in bucket so pointer to NULL
            p->next = NULL;
        }
        else
        {
            // Not first item in bucket so pointer to first item in list (LINKED LIST THEORY)
            p->next = table[hash_value];
        }
        // Point bucket to new node
        table[hash_value] = p;

        // Update size of dict
        count++;
    }

    // Close file
    fclose(dict_file);

    return true;
}

// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
    // No need to insert if function to check if dict loaded since count is already set to 0 (it will return 0 if not loaded)
    return count;
}

// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
    // Iterate through all buckets of hash table
    for (int i = 0; i < N; i++)
    {
        // Access hash's table bucket
        node *p = table[i];

        // Loop through all items (linked list) in bucket
        while (p != NULL)
        {
            // Use trav pointer not to orphan list
            node *trav = p;
            // Point to next element in list
            p = p->next;
            // Free trav
            free(trav);
        }

        // End of loop condition to return true
        if (p == NULL && i == N - 1)
        {
            return true;
        }
    }
    return false;
}

问题根源

  • 哈希表未初始化:全局数组table[N]声明后没有初始化,元素是随机的垃圾指针。load函数中访问table[hash_value]时,可能读取到无效地址触发段错误。check50的测试环境可能默认初始化了全局变量,因此未发现该问题。
  • 文件打开判断逻辑错误:load函数中判断if (dictionary == NULL)是错误的,应该检查dict_file == NULL——要验证的是文件是否成功打开,而非传入的文件名指针是否为空。

修复方案

  1. 初始化哈希表:在load函数开头添加循环,将所有桶初始化为NULL:
// 初始化哈希表所有桶
for (int i = 0; i < N; i++)
{
    table[i] = NULL;
}

或者直接在全局声明时初始化:node *table[N] = {NULL};(大数组在CS50环境下可正常使用)。

  1. 修正文件打开判断:将if (dictionary == NULL)改为if (dict_file == NULL),确保正确检测文件打开失败的情况。

  2. 可选优化哈希函数:将哈希函数改为x = (x * 31) + toupper(word[i]),减少哈希碰撞,同时降低数值溢出风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:55:08