CS50 pset5中dictionary.c的load函数触发Segmentation Fault问题求助
问题根因与修复方案
你遇到的SIGSEGV错误是多个代码问题共同导致的,核心问题如下:
必现错误点
- fopen未做空指针校验
调用fopen(dictionary, "r")后没有判断返回值是否为NULL,若字典文件路径错误、无权限读取或不存在,file为NULL,后续fread访问空指针直接触发段错误。 - 单词长度无边界检查
读取字符存入tmpW时没有判断wordIndex是否超过LENGTH,如果字典中存在长度超过LENGTH的单词,会直接越界写tmpW数组,造成栈溢出,触发段错误。 - 传入hash函数的字符串未以'\0'结尾
遇到换行符处理单词前,没有给当前tmpW里的单词末尾补'\0',如果你的hash函数是按C风格字符串(以'\0'为结束标志)实现的,会越界读取tmpW之外的内存,导致哈希计算结果异常:
若哈希返回负数,你用int类型的tableIndex存储,访问table[负数]会指向非法内存地址,符合Valgrind报的Bad permissions for mapped region错误。
其他逻辑缺陷
while(fread)循环内的else分支永远不会执行:只要进入循环体,fread就成功读取了1个字符,c要么是'\n'要么不是,不可能走到第三个分支,这段逻辑无效。malloc失败时的处理错误:load函数返回值为bool类型,你当前返回1等价于返回true,不符合错误场景的返回要求,且失败时未关闭已打开的文件,会造成资源泄漏。- 复制
tmpW到node->word的逻辑冗余:不需要逐字符循环复制,直接用strcpy即可,前提是先保证tmpW是合法的'\0'结尾字符串。
修复代码示例
bool load(const char *dictionary) { // 初始化哈希表 for (int i = 0; i < N; i++) { table[i] = NULL; } int wordIndex = 0; int tableIndex = 0; char tmpW[LENGTH + 1]; char c; FILE *file = fopen(dictionary, "r"); // 新增fopen空校验 if (file == NULL) { return false; } while (fread(&c, sizeof(char), 1, file)) { if (c != '\n') { // 新增单词长度边界检查 if (wordIndex < LENGTH) { tmpW[wordIndex] = c; wordIndex++; } } else { // 给当前单词补结束符 tmpW[wordIndex] = '\0'; wordIndex = 0; node *n = malloc(sizeof(node)); if (n == NULL) { fclose(file); // malloc失败先关文件 return false; // 返回错误标识 } tableIndex = hash(tmpW); // 可选:增加tableIndex合法性校验,避免hash实现异常导致越界 if (tableIndex < 0 || tableIndex >= N) { free(n); continue; } strcpy(n->word, tmpW); n->next = table[tableIndex]; table[tableIndex] = n; wordCount++; } } fclose(file); return true; }
内容的提问来源于stack exchange,提问作者Chicha
相关产品推荐
相关产品推荐

