如何调试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——要验证的是文件是否成功打开,而非传入的文件名指针是否为空。
修复方案
- 初始化哈希表:在
load函数开头添加循环,将所有桶初始化为NULL:
// 初始化哈希表所有桶 for (int i = 0; i < N; i++) { table[i] = NULL; }
或者直接在全局声明时初始化:node *table[N] = {NULL};(大数组在CS50环境下可正常使用)。
修正文件打开判断:将
if (dictionary == NULL)改为if (dict_file == NULL),确保正确检测文件打开失败的情况。可选优化哈希函数:将哈希函数改为
x = (x * 31) + toupper(word[i]),减少哈希碰撞,同时降低数值溢出风险。
内容的提问来源于stack exchange,提问作者Gianluca
相关产品推荐
相关产品推荐

