CS50 Pset5 Speller程序出现Segmentation Fault问题求助
问题分析与修复方案
方案可行性
哈希表结合字典树的方案完全可行——用哈希表对单词首字母分组,每个桶对应一棵字典树,既保留哈希表的快速定位特性,又利用字典树的空间效率,是合理的设计思路。
代码中的错误(段错误根源)
1. 哈希函数与哈希表桶数不匹配
你的哈希函数返回tolower(word[0]) - 'a',结果范围是0-25,但哈希表桶数N=71。初始化时只给前26个桶分配了内存,剩下的26-70号桶为全局默认的NULL值。unload函数遍历所有71个桶时,会对NULL指针调用current->children[i],直接触发段错误。
修复:
将哈希表桶数改为26,与哈希函数输出范围匹配:
const unsigned int N = 26;
同时把load函数中初始化循环的条件从z<71改为z<N。
2. 哈希表节点初始化不完整
初始化哈希表桶时,未设置is_word属性的值,全局结构体的该字段会是随机垃圾值,可能导致后续逻辑判断错误,甚至触发内存访问异常。
修复:
初始化每个桶节点时显式设置is_word为false:
for (int z = 0; z<N; z++) { table[z] = malloc(sizeof(node)); table[z]->is_word = false; // 新增该行 for (int i = 0; i<26; i++) { table[z]->children[i] = NULL; } }
3. 文件打开失败的返回值错误
load函数中文件打开失败时返回1,但根据函数定义,应返回false(即0)表示加载失败。错误的返回值会让调用者误以为加载成功,后续操作触发异常。
修复:
将返回值改为false:
if (file == NULL) { printf("Could not open %s.\n", dictionary); unload(); return false; }
4. 未处理文件末尾的剩余单词
当文件读取到EOF时,如果index>0(存在未处理的单词),不会进入处理分支,导致最后一个单词无法被加载,还可能残留无效数据引发错误。
修复:
在while循环结束后添加剩余单词处理逻辑:
while (fread(&c, sizeof(char), 1, file)) { // 原循环内逻辑不变 } // 新增:处理文件末尾的剩余单词 if (index > 0) { word[index] = '\0'; word_count +=1; int hashword = hash(word); node *cursor = table[hashword]; for (int j = 0; j<index; j++) { int letterindex = tolower(word[j]) - 'a'; if (cursor->children[letterindex] == NULL) { node *new = malloc(sizeof(node)); if (new == NULL) { printf("ERROR NULL!"); return false; } new->is_word = false; for (int k = 0; k<26; k++) { new->children[k] = NULL; } cursor->children[letterindex] = new; } cursor = cursor->children[letterindex]; } cursor->is_word = true; }
总结
你的方案完全可行,段错误是由代码中的具体bug导致的,修复上述问题后程序即可正常运行。
内容的提问来源于stack exchange,提问作者KHeisenberg
相关产品推荐
相关产品推荐

