哈希表打印函数异常:文件读取的person结构体无法正常显示
哈希表插入文件读取结构体异常问题排查
问题描述
手动创建的person结构体插入哈希表后能正常输出,但从文本文件读取创建的person结构体却无法正常显示,程序需要正确展示哈希表的索引与字符串键值对。
原代码
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <time.h> #define MAX_NAME 256 #define TABLE_SIZE 20 typedef struct { char *name; int age; } person; person * hash_table[TABLE_SIZE]; unsigned int hash(char *name) { unsigned int hash_value = 0; int length = strnlen(name, MAX_NAME); for (int i = 0; i < length; i++) { hash_value += name[i]; hash_value = (hash_value * name[i]) % TABLE_SIZE; } return hash_value; } void init_hash_table(void) { for (int i = 0; i < TABLE_SIZE; i++) { hash_table[i] = NULL; } } void print_table(void) { for (int m = 0; m < TABLE_SIZE; m++) { if (hash_table[m] == NULL) { printf("\t%i\t---\n", m); } else { printf("\t%i\t%s\n", m, hash_table[m]->name); } } } bool hash_table_insert(person *p) { if (p == NULL) return false; int index = hash(p->name); printf("%d\n", index); if (hash_table[index] != NULL) { return false; } hash_table[index] = p; printf("Inserted %s\n", p->name); return true; } int main(int argc, char *argv[]) { FILE *file = fopen(argv[1], "r"); char buffer[MAX_NAME]; unsigned int hash_counts[TABLE_SIZE]; unsigned char count; srand(time(NULL)); init_hash_table(); print_table(); if (file == NULL) { printf("Error\n"); exit(-1); } person p1 = {.name ="JACOB", .age=10}; person p2 = {.name ="ANDRE", .age=13}; person p3 = {.name ="MARCUS", .age=23}; hash_table_insert(&p1); hash_table_insert(&p2); hash_table_insert(&p3); while (fscanf(file, "%s", buffer) == 1 && count < TABLE_SIZE) { count++; hash_counts[hash(buffer)]++; person p1 = {.name = buffer, .age = rand() % 100}; hash_table_insert(&p1); } print_table(); /* for (int j = 0; j < TABLE_SIZE; j++) { printf("%-3d: ", j); for (int k = 0; k < hash_counts[j]; k++) { printf("x"); } printf("\n"); } */ }
输入示例
Isidoro Mechelle Etta Cozmo Torey Gizela Ludvig Gaby Bud Skipp Lura Linda Mathilda Carlynne Felix Roosevelt Norbert Renee Holly Keefer Zachariah Felice Collie Arielle Langsdon Teodora Tine Floris Annmarie Anita Boycey Conway Beverlee Derril Ann-marie Cori Hanny ...
输出示例
0 --- 1 --- 2 --- 3 --- 4 --- 5 --- 6 --- 7 --- 8 --- 9 --- 10 --- 11 --- 12 --- 13 --- 14 --- 15 --- 16 --- 17 --- 18 --- 19 --- 0 Zachariah 1 Zachariah 2 Zachariah 3 --- 4 Zachariah 5 ANDRE 6 --- 7 --- 8 Zachariah 9 Zachariah 10 --- 11 Zachariah 12 Zachariah 13 Zachariah 14 --- 15 --- 16 Zachariah 17 Zachariah 18 JACOB 19 MARCUS
问题根源
局部变量生命周期失效:while循环内创建的
person p1是循环体的局部变量,每次循环结束后该变量的内存会被回收。哈希表中存储的是这个局部变量的指针,后续访问时指针指向已释放的内存(野指针),读取到的是垃圾数据,导致所有从文件插入的条目显示成最后一次读取的内容或乱码。而手动创建的p1/p2/p3是main函数的局部变量,生命周期覆盖整个main函数执行过程,所以能正常显示。未初始化变量:
unsigned char count;未初始化,初始值是随机垃圾值,可能导致循环无法正常执行(比如初始值大于等于TABLE_SIZE,循环直接跳过)。字符串共享缓冲区:所有从文件读取的person的
name都指向同一个buffer数组,每次循环读取新内容会覆盖之前的字符串,就算指针有效,所有条目也会显示最后一次读取的内容。
修复方案
- 为每个从文件读取的person动态分配内存,并复制字符串到新内存,避免局部变量生命周期和缓冲区共享问题。
- 初始化
count为0,确保循环逻辑正常。 - 程序结束前释放动态分配的内存,避免内存泄漏。
修改后的代码
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <time.h> #define MAX_NAME 256 #define TABLE_SIZE 20 typedef struct { char *name; int age; } person; person * hash_table[TABLE_SIZE]; unsigned int hash(char *name) { unsigned int hash_value = 0; int length = strnlen(name, MAX_NAME); for (int i = 0; i < length; i++) { hash_value += name[i]; hash_value = (hash_value * name[i]) % TABLE_SIZE; } return hash_value; } void init_hash_table(void) { for (int i = 0; i < TABLE_SIZE; i++) { hash_table[i] = NULL; } } void print_table(void) { for (int m = 0; m < TABLE_SIZE; m++) { if (hash_table[m] == NULL) { printf("\t%i\t---\n", m); } else { printf("\t%i\t%s\n", m, hash_table[m]->name); } } } bool hash_table_insert(person *p) { if (p == NULL) return false; int index = hash(p->name); if (hash_table[index] != NULL) { return false; } hash_table[index] = p; printf("Inserted %s\n", p->name); return true; } int main(int argc, char *argv[]) { FILE *file = fopen(argv[1], "r"); char buffer[MAX_NAME]; unsigned int hash_counts[TABLE_SIZE] = {0}; unsigned char count = 0; srand(time(NULL)); init_hash_table(); print_table(); if (file == NULL) { printf("Error\n"); exit(-1); } person p1 = {.name ="JACOB", .age=10}; person p2 = {.name ="ANDRE", .age=13}; person p3 = {.name ="MARCUS", .age=23}; hash_table_insert(&p1); hash_table_insert(&p2); hash_table_insert(&p3); while (fscanf(file, "%s", buffer) == 1 && count < TABLE_SIZE) { count++; unsigned int h = hash(buffer); hash_counts[h]++; person *new_person = malloc(sizeof(person)); if (new_person == NULL) { printf("Memory allocation failed\n"); continue; } new_person->name = malloc(strlen(buffer) + 1); if (new_person->name == NULL) { free(new_person); printf("Memory allocation failed for name\n"); continue; } strcpy(new_person->name, buffer); new_person->age = rand() % 100; hash_table_insert(new_person); } print_table(); // 释放动态分配的内存 for (int i = 0; i < TABLE_SIZE; i++) { if (hash_table[i] != NULL && hash_table[i] != &p1 && hash_table[i] != &p2 && hash_table[i] != &p3) { free(hash_table[i]->name); free(hash_table[i]); } } fclose(file); return 0; }
内容的提问来源于stack exchange,提问作者pher
相关产品推荐
相关产品推荐

