You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

哈希表释放节点后触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 01:01:20