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
相关产品推荐
相关产品推荐

