哈希表释放节点后触发Segmentation Fault问题求助
C语言哈希表实现的段错误问题排查
以下是我编写的C语言哈希表实现代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define size 9900 int count = 1; struct membership { char name[100]; char gender[100]; char code[100]; int age; int weight; struct membership* next; }*table[size]; typedef struct membership member; member *newMember(char name[], char gender[], char code[], int age, int weight){ member *node = (member*)malloc(sizeof(member)); strcpy(node->name, name); strcpy(node->gender, gender); strcpy(node->code, code); node->age = age; node->weight = weight; node->next = NULL; return node; } int asciiSum(char str[]){ int sum = 0; for(int i = 0; str[i] != '\0'; i++){ sum += str[i]; } return sum; } int hash(char code[]){ return asciiSum(code)%size; } // insert recursive member *insertRec(member *curr, char name[], char gender[], char code[], int age, int weight){ if (!curr){ return newMember(name, gender, code, age, weight); } curr->next = insertRec(curr->next, name, gender, code, age, weight); return curr; } // insert biasa void insert(char name[], char gender[], char code[], int age, int weight){ int key = hash(code); table[key] = insertRec(table[key], name, gender, code, age, weight); } void viewMember(){ printf("| %-5s | %-20s | %-20s | %-20s | %-20s | %-15s |\n", "no", "member name", "member age", "member weight", "member gender", "member code"); int j = 0; for (int i = 0; i < size; i++) { member *curr = table[i]; while (curr) { printf("| %-5d | %-20s | %-20d | %-20d | %-20s | %-15s |\n", ++j, curr->name, curr->age, curr->weight, curr->gender, curr->code); curr = curr->next; } } } member *searchRec(member *curr, char *code){ if (!curr) return NULL; if(!strcmp(curr->code, code))return curr; return searchRec(curr->next, code); } member *deleteRec(member *curr, char *code){ if (!curr) return NULL; if (!strcmp(curr->code, code)){ free(curr); return curr->next; } curr->next = deleteRec(curr->next, code); return curr; } void deleteProduct(char *code){ int key = hash(code); member *node = searchRec(table[key], code); if (!node) { printf("%s not found\n", code); return; } printf("Deleted %s\n", node->name); table[key] = deleteRec(table[key], code); } int main(){ insert("tono", "male", "61TOM102", 21, 40); insert("tini", "female", "61TIF102", 21, 40); insert("didi", "male", "102DIM102", 21, 40); deleteProduct("61TOM102"); viewMember(); return 0; }
运行该代码后出现zsh: segmentation fault错误。我的预期是释放tono节点后,正常打印剩余成员信息;但实际运行触发了段错误。我怀疑错误出在deleteRec或viewMember函数中,推测是释放内存后访问了无效内存区域。另外,该代码在在线编译器中运行正常,请问这是什么原因?能否提供解决提示?
问题原因
段错误的直接原因在deleteRec函数里:当找到要删除的节点时,你先调用free(curr)释放了该节点的内存,之后又试图访问curr->next返回给上层调用。此时curr已经是被释放的无效内存,访问它的成员属于非法内存访问,触发段错误。
在线编译器能正常运行是因为不同环境的内存检测机制不同——有些在线编译器的内存管理器不会立即回收已释放的内存块,或者对非法访问的检测没那么严格,所以侥幸没触发错误,但这个写法本身是严重的未定义行为。
解决提示
修改deleteRec函数,在释放节点之前先保存curr->next的指针,再返回这个保存的指针:
member *deleteRec(member *curr, char *code){ if (!curr) return NULL; if (!strcmp(curr->code, code)){ member *nextNode = curr->next; // 先保存下一个节点的指针 free(curr); return nextNode; // 返回保存的指针,而不是访问已释放的curr } curr->next = deleteRec(curr->next, code); return curr; }
这样就能避免访问已释放的内存,解决段错误问题。
内容的提问来源于stack exchange,提问作者average_c_enjoyer
相关产品推荐
相关产品推荐

