哈希表插入函数仅保留最新输入问题排查与malloc用法求助
哈希表程序问题修复方案
问题概述
insert函数仅能保存从text.txt读取的最新字符串- 核心需求:
- 解析
"Finn 34"格式的行,将字符串与对应数值插入哈希表 - 哈希索引已有内容时报告冲突
- 插入重复字符串时提示已存在
- 解析
- 当前所有字符串指向同一个
fscanf读取的name变量,需通过内存分配解决,但多次尝试未成功
现有代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define TableSize 45 #define Max 50 ///// dont forget the edit in main typedef struct node { char name[Max]; int value; } node; node array[Max]; void init_array(){ for (int i = 0; i < TableSize; i++){ //array[i] = NULL; } } void insert(int index, node *p){ /*char * tempName = malloc (sizeof (char) * 50); strcpy(tempName, p->name);*/ if (array[index].value != 0){ //if (array[index]->name == p->name){ if (strcmp(array[index].name, p->name) == 0){ printf("Error %s already exists at index %d\n", array[index].name, index); } else{ printf("Collision occured at index %d with\n", index); } } else{ array[index] = *p; strcpy(array[index].name, p->name); printf("Stored %s with value of %d at index %d.\n", array[index].name, array[index].value, index); } } int hash(char name[Max]){ int key = 0; for (int i = 0; name[i] != '\0'; ++i){ char x = name[i]; key = key + x; } key = key % TableSize; return key; } int main(int argc, char *argv[]) { init_array(); FILE *fp; char ch; char name[Max]; int x, HaValue; fp = fopen(argv[1], "r"); if (NULL == fp) { //printf("file can't be opened \n"); fp = fopen("text.txt", "r"); ///////get rid of when done } node * p; p = malloc(sizeof(struct node)); do{ x = 0; int counter = 0; if (fscanf(fp, "%49s", name) != 1) break; if (fscanf(fp, "%d", &x) != 1) counter = 1; HaValue = hash(name); p->value = x; strcpy(p->name, name); if (counter != 0) { } else{ insert(HaValue, p); } } while(!feof(fp)); printf("%d %s %d", 12, array[12].name, array[12].value); //test to see if the name was correctly saved. should be "12 Dog 12" // Closing the file fclose(fp); return 0; }
测试文件内容(text.txt)
Brom 89 Paul 25 Jake 34 Yokai 45 Jake Dog 20 Paul 30 Brom Kron 40 Finn 234
核心问题分析
- 哈希表数组定义错误:
array大小设为Max,但实际应该与TableSize一致,存在索引越界风险 - 初始化不完整:
init_array未清空结构体的name和value,空节点判断逻辑(value != 0)不可靠 - 重复使用单个动态节点:
main中仅分配一个node指针,每次循环覆盖内容,导致所有插入项指向同一块内存,最终只保留最后一次读取的数据 - 文件读取逻辑缺陷:
do-while(!feof)会导致最后一行重复读取 - 插入逻辑冗余:
array[index] = *p;已完成结构体复制,后续strcpy完全多余
修复后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define TableSize 45 #define Max 50 typedef struct node { char name[Max]; int value; } node; // 修正哈希表数组大小为TableSize node array[TableSize]; void init_array(){ // 初始化每个空节点:清空字符串,标记value为0 for (int i = 0; i < TableSize; i++){ memset(array[i].name, 0, Max); array[i].value = 0; } } void insert(int index, node *p){ if (array[index].value != 0){ if (strcmp(array[index].name, p->name) == 0){ printf("错误:%s 已存在于索引 %d\n", array[index].name, index); } else{ printf("冲突发生在索引 %d,与已存在的键 %s 冲突\n", index, array[index].name); } } else{ array[index] = *p; printf("已存储 %s,值为 %d,索引为 %d\n", array[index].name, array[index].value, index); } } int hash(char name[Max]){ int key = 0; for (int i = 0; name[i] != '\0'; ++i){ key += name[i]; } return key % TableSize; } int main(int argc, char *argv[]) { init_array(); FILE *fp = NULL; // 优先使用命令行参数指定的文件,无参数则尝试打开text.txt if (argc >= 2) { fp = fopen(argv[1], "r"); } if (fp == NULL) { fp = fopen("text.txt", "r"); if (fp == NULL) { printf("无法打开文件\n"); return 1; } } char name[Max]; int x; // 修复读取逻辑:成功读取字符串+整数才处理 while (fscanf(fp, "%49s %d", name, &x) == 2) { // 栈上创建临时节点,避免重复覆盖内存 node temp_node; strcpy(temp_node.name, name); temp_node.value = x; int ha_value = hash(name); insert(ha_value, &temp_node); } // 测试输出索引12的内容 printf("索引12的内容:%s %d\n", array[12].name, array[12].value); fclose(fp); return 0; }
关键修改说明
- 修正哈希表数组大小:确保数组大小与哈希表尺寸
TableSize一致,避免索引越界 - 完善初始化:用
memset清空字符串,设置value为0,保证空节点判断准确 - 替换动态节点为栈临时节点:每次读取后在栈上创建独立的
node,避免内存覆盖问题,无需手动malloc/free - 修复文件读取逻辑:用
while(fscanf(...) == 2)替代do-while(!feof),彻底解决重复读取问题 - 优化提示信息:冲突时打印已存在的键名,提升调试可读性
- 移除冗余代码:删除重复的
strcpy调用,简化插入逻辑
可选:链式哈希表实现(支持冲突链式存储)
如果需要支持冲突的链式解决(而非仅报告冲突),可以修改为指针数组+动态节点:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define TableSize 45 #define Max 50 typedef struct node { char name[Max]; int value; struct node *next; } node; // 哈希表改为指针数组,初始为NULL node *array[TableSize]; void init_array(){ for (int i = 0; i < TableSize; i++){ array[i] = NULL; } } void insert(int index, char *name, int value){ // 检查当前索引是否已存在相同键 node *current = array[index]; while (current != NULL) { if (strcmp(current->name, name) == 0) { printf("错误:%s 已存在于索引 %d\n", name, index); return; } current = current->next; } // 动态分配新节点 node *new_node = malloc(sizeof(node)); if (new_node == NULL) { printf("内存分配失败\n"); return; } strcpy(new_node->name, name); new_node->value = value; new_node->next = array[index]; // 提示冲突或成功存储 if (array[index] != NULL) { printf("冲突发生在索引 %d,已通过链式存储解决\n", index); } else { printf("已存储 %s,值为 %d,索引为 %d\n", name, value, index); } array[index] = new_node; } int hash(char name[Max]){ int key = 0; for (int i = 0; name[i] != '\0'; ++i){ key += name[i]; } return key % TableSize; } int main(int argc, char *argv[]) { init_array(); FILE *fp = NULL; if (argc >= 2) { fp = fopen(argv[1], "r"); } if (fp == NULL) { fp = fopen("text.txt", "r"); if (fp == NULL) { printf("无法打开文件\n"); return 1; } } char name[Max]; int x; while (fscanf(fp, "%49s %d", name, &x) == 2) { int ha_value = hash(name); insert(ha_value, name, x); } // 打印所有哈希表内容(可选) for (int i = 0; i < TableSize; i++){ if (array[i] != NULL){ printf("索引%d:", i); node *current = array[i]; while (current != NULL){ printf("%s(%d) -> ", current->name, current->value); current = current->next; } printf("NULL\n"); } } fclose(fp); return 0; }
内容的提问来源于stack exchange,提问作者MC_ Spire
相关产品推荐
相关产品推荐

