CS50拼写器作业:malloc初始正常,循环多次后报corrupted top size错误
CS50 Speller作业:
malloc(): corrupted top size错误分析 我正在完成CS50的拼写器作业,仅修改了dictionary.c文件,使用djb2哈希算法实现。运行时出现错误:
malloc(): corrupted top size Aborted (core dumped)
调试发现加载前10个词(直至aardwolf)正常,存入aardwolf后调用malloc触发错误。以下是我的代码:
// Implements a dictionary's functionality #include <ctype.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.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 = 100; // Variable to count number of words loaded into dictionary int count = 0; // Hash table node *table[N]; // Returns true if word is in dictionary, else false bool check(const char *word) { // TODO return false; } // Hashes word to a number unsigned int hash(const char *word) { // Improve this hash function unsigned long hash = 5381; int c; while((c = *word++)) { hash = (((hash << 5) + hash) + c); } int hash_value = hash % N; return hash_value; } // Loads dictionary into memory, returning true if successful, else false bool load(const char *dictionary) { // TODO FILE *dict_file = fopen(dictionary, "r"); if (dict_file == NULL) { printf("Could not open %s.\n", dictionary); return false; } for(int i = 0; i < N; i++) { table[i] = NULL; } char c; int i = 0; node *new_node = malloc(sizeof(node)); while (fread(&c, sizeof(char), 1, dict_file)) { // printf("%c", c); if(c != '\n') { new_node -> word[i] = c; i++; } else { int key = hash(new_node -> word); new_node -> next = table[key]; table[key] = new_node; // printf("%lu", sizeof(node)); new_node = malloc(sizeof(node)); count++; } } fclose(dict_file); if(count > 0) { return true; } else { return false; } } // Returns number of words in dictionary if loaded, else 0 if not yet loaded unsigned int size(void) { // TODO if(count > 0) { return count; } else { return 0; } } // Unloads dictionary from memory, returning true if successful, else false bool unload(void) { // TODO for(int i = 0; i < N; i++) { node *temp_node = NULL; while(table[i] != NULL) { temp_node = table[i] -> next; free(table[i]); table[i] = temp_node; } } return false; }
错误原因分析
字符串未添加终止符:
读取单词时,遇到换行符直接存入哈希表,但new_node->word数组没有添加'\0'。hash函数会一直读取内存直到遇到0字节,这会越界访问node结构体之外的堆内存,破坏堆的元数据。未重置单词索引
i:
每个单词处理完后,i没有重置为0,下一个单词会从word数组的当前位置继续写入,直接覆盖node结构体中的next指针区域,彻底破坏堆结构,导致后续malloc检测到堆损坏并抛出错误。最后一个单词未处理:
如果字典文件最后一行没有换行符,最后一个单词永远不会被加入哈希表,还会残留一个未使用的malloc节点,可能引发额外内存问题。unload函数返回错误值:
虽然不是直接导致当前错误,但unload函数完成内存释放后返回false,属于逻辑错误。
修正后的关键代码片段
修改load函数中的换行处理逻辑,添加字符串终止符并重置索引:
else { new_node->word[i] = '\0'; // 添加字符串终止符 int key = hash(new_node->word); new_node->next = table[key]; table[key] = new_node; count++; i = 0; // 重置索引,准备下一个单词 new_node = malloc(sizeof(node)); // 检查内存分配是否成功 if (new_node == NULL) { fclose(dict_file); unload(); return false; } }
循环结束后处理最后一个无换行符的单词:
// 处理文件末尾没有换行符的最后一个单词 if (i > 0) { new_node->word[i] = '\0'; int key = hash(new_node->word); new_node->next = table[key]; table[key] = new_node; count++; } else { // 释放未使用的节点 free(new_node); }
同时修正unload函数的返回值:
bool unload(void) { for(int i = 0; i < N; i++) { node *temp_node = NULL; while(table[i] != NULL) { temp_node = table[i]->next; free(table[i]); table[i] = temp_node; } } return true; // 释放成功返回true }
内容的提问来源于stack exchange,提问作者esp
相关产品推荐
相关产品推荐

