C语言:如何保留结构体内存防止被覆盖?哈希表链表节点改写求助
分离链接哈希表内存覆盖问题的修复方案
核心问题分析
你的代码出现内存覆盖、节点数据乱码的根本原因是所有链表节点、链表结构都在栈上分配局部变量,函数执行完毕后栈帧被销毁,这些内存会被后续函数(比如hash、tableGet)的栈数据覆盖。除此之外还有几个细节错误:
- 字符串比较用
==,这是比较指针地址而非内容,应该用strcmp - 哈希函数里的
sum未初始化,会导致哈希值随机,定位错误的哈希桶 - 哈希表和链表操作采用传值调用,会产生不必要的拷贝,也容易引发内存问题
修复步骤
- 改用堆内存分配:用
malloc为Node、List分配堆内存,确保函数返回后内存不会被回收 - 修复字符串比较逻辑:用
strcmp替代==比较姓名 - 初始化哈希函数的
sum变量:避免随机哈希值 - 修改函数为指针传递:哈希表的添加、查询操作都传递指针,避免拷贝,保证操作作用于原表
- 修正链表操作的指针逻辑:确保链表节点的指针指向堆内存的有效地址
完整修复代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdbool.h> typedef struct Node { int val; int savedAge; char savedName[100]; struct Node* next; } Node; typedef struct { int age; char name[100]; } Person; typedef struct { Node* head; Node* tail; } List; typedef struct { List* table[100]; } HashTable; int hash(Person*); Person person(int age, char name[]) { Person p; p.age = age; strcpy(p.name, name); return p; } // 动态创建节点 Node* createNode(int val, Person p, Node* next) { Node* n = (Node*)malloc(sizeof(Node)); if (!n) { perror("malloc failed for Node"); exit(EXIT_FAILURE); } n->val = val; strcpy(n->savedName, p.name); n->savedAge = p.age; n->next = next; return n; } // 动态创建带头节点的链表 List* createList() { List* l = (List*)malloc(sizeof(List)); if (!l) { perror("malloc failed for List"); exit(EXIT_FAILURE); } // 创建哨兵节点 l->head = createNode(-1, person(0, "SENTINEL"), NULL); l->tail = l->head; return l; } // 向链表添加节点 void listAdd(List* l, int val, Person p) { Node* newNode = createNode(val, p, NULL); l->tail->next = newNode; l->tail = newNode; } // 初始化哈希表 HashTable* createHashTable() { HashTable* t = (HashTable*)malloc(sizeof(HashTable)); if (!t) { perror("malloc failed for HashTable"); exit(EXIT_FAILURE); } // 初始化所有桶为NULL for (int i = 0; i < 100; i++) { t->table[i] = NULL; } return t; } // 向哈希表添加键值对 void tableAdd(HashTable* t, Person key, int val) { int num = hash(&key) % 100; // 处理负数哈希值(如果有的话) if (num < 0) num += 100; if (t->table[num] == NULL) { t->table[num] = createList(); } listAdd(t->table[num], val, key); } // 从哈希表查询值 int tableGet(HashTable* t, Person key) { int position = hash(&key) % 100; if (position < 0) position += 100; List* listLoc = t->table[position]; if (listLoc == NULL) { return -1; } Node* curr = listLoc->head->next; // 跳过哨兵节点 while (curr != NULL) { if (curr->savedAge == key.age && strcmp(curr->savedName, key.name) == 0) { return curr->val; } curr = curr->next; } return -1; } // 修复后的哈希函数 int hash(Person* p) { int sum = 0; // 初始化sum int i = 0; char nameChar = p->name[i]; while (nameChar != '\0'){ sum += (int)nameChar; i += 1; nameChar = p->name[i]; } return p->age + sum; } // 清理哈希表内存(可选,避免内存泄漏) void freeHashTable(HashTable* t) { for (int i = 0; i < 100; i++) { if (t->table[i] != NULL) { Node* curr = t->table[i]->head; while (curr != NULL) { Node* temp = curr; curr = curr->next; free(temp); } free(t->table[i]); } } free(t); } int main() { Person bob = person(36, "Robert"); printf("%s\n", bob.name); HashTable* tab = createHashTable(); tableAdd(tab, bob, 3); printf("Added Robert to table as 3\n"); int val = tableGet(tab, bob); if (val == 3) { printf("Success!\n"); } else { printf("Failure, val is %d\n", val); } freeHashTable(tab); // 释放内存 return 0; }
关键修复说明
- 新增
createNode、createList、createHashTable函数,用malloc分配堆内存,确保内存长期有效 listAdd直接创建新节点并添加,不再依赖局部变量tableGet直接遍历指针,避免拷贝节点导致的栈问题,同时用strcmp比较姓名- 哈希函数初始化
sum为0,避免随机值 - 添加内存清理函数
freeHashTable,避免内存泄漏 - 所有哈希表操作都传递指针,避免拷贝整个哈希表的开销和错误
内容的提问来源于stack exchange,提问作者Mark Pock
相关产品推荐
相关产品推荐

