散列 table 值被覆盖的问题

Hash table problems with values getting overwritten

我第一次测试哈希 tables,我得到了一个奇怪的错误。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 40

typedef struct snode {
    char *nome;
    struct snode *next;
} TNode;

typedef TNode *TList;

typedef struct tht {
    TList *buckets;
    int nbuckets;
} THT;

TList Create_List();
TNode *Create_Node(char *);
TList Insert_List(TList, char *);
THT *Create_THT(int n);
void HT_Print(THT *ht);
THT *Insert_THT(THT *ht, char *name, int key);
int hash(char *name);
void Print_List(TList list);

int main() {
    THT *ht = Create_THT(5);
    char name[MAX];
    int key, contr;
    printf("INSERISCI 0 PER USCIRE O INSERIRE NOME \n");
    do {
        printf("\n INSERIRE NOME : ");
        scanf("%s", &name);  //AFTER THE SECOND INSERTION FROM THIS LANE VALUES CHANGE INSIDE ht?? why 
        key = hash(name);
        ht = Insert_THT(ht, name, key);
        printf("\n Inserisci 1 per continuare 0 per terminare ");
        scanf("%d", &contr);

    } while (contr != 0);
    HT_Print(ht);
    return 0;
}

TList Create_List() {
    return NULL;
}

TNode *Create_Node(char nome[MAX]) {
    TNode *node;
    node = malloc(sizeof(TNode));
    node->nome = nome;
    node->next = NULL;
    return node;
}

TList Insert_List(TList list, char info[MAX]) {
    TNode *tmp;
    TNode *node;
    node = Create_Node(info);
    tmp = list;
    if (list == NULL) {
        list = node;
    } else {
        while (tmp->next != NULL) {
            tmp = tmp->next;
        }
        tmp->next = node;
    }
    return list;
}

THT *Create_THT(int n) {
    int i;
    THT *ht = malloc(sizeof(THT));

    ht->buckets = malloc(n * sizeof(TList));
    for (i = 0; i < n; i++) {
        ht->buckets[i] = Create_List();
    }
    ht->nbuckets = n;
    return ht;
}

void HT_Print(THT *ht) {
    int i;
    for (i = 0; i < ht->nbuckets; i++) {
        Print_List(ht->buckets[i]);
    }
}

int hash(char *name) {
    return (name[0] - 'a');
}

THT *Insert_THT(THT *ht, char name[MAX], int key) {
    ht->buckets[key] = Insert_List(ht->buckets[key], name);
    return ht;
}

void Print_List(TList list) {
    while (list != NULL) {
        printf("%s", list->nome);
        list = list->next;
    }
}

我用调试测试了它。第一次插入时没问题(例如我插入 adam),但随后发生了一些奇怪的事情。 第二次,当我输入名称 bob 时(因为它就像一个名称词汇表),我检查了 ht->buckets 的值,里面有些东西发生了变化。

我不明白我什至没有进入有效修改我的散列 table (ht) 中的内容的函数,并且它内部发生了变化。我快疯了,我试图找到一个解决方案,但我真的不明白如何从一个不必处理我的 HT 的结构值在该结构内发生变化的主命令...

无关,但使用英文名称和输出对每个人来说都更容易。


只是一个猜测,但在 Create_Node 中,您为新节点分配了内存,但没有为名称 (nome) 分配内存。

您只需将指针复制到传递的数组,每次插入新名称时都会更改。为名称分配内存并复制内容而不是指针应该可以解决这个问题,例如

node->nome = strdup(nome);

不要忘记,当您在更大的上下文中使用哈希时,您最终必须清理哈希和名称,这意味着为节点和名称释放内存

free(node->nome);
free(node);

Create_Node 收到指向 main 中数组 name 的指针。每次输入新名称时都会重复使用此数组。这意味着,所有节点都指向同一个数组,因此所有节点都打印相同的(最后输入的)名称。

为每个节点分配单独的内存并将数组复制到此内存 (strdup),解决了问题。

你的代码有很多问题:

  • 您在 typedef TNode *TList; 中将指针隐藏在 typedef 后面,这很容易出错并且会让代码的读者感到困惑。
  • CreateNode 不会复制 name 指向的内存。鉴于您如何使用此函数,所有节点共享同一个数组,因此所有节点都具有相同的名称。使用node->nome = strdup(nome);解决这个问题。
  • scanf("%s", &name); 不正确:& 是多余的,您应该指定要存储到 name 的最大字符数以避免缓冲区溢出。使用 scanf("%39s", name);。此外,您应该测试 return 值以检测意外的文件结尾。
  • Print_List 不分隔名称。使用 printf("%s\n", list->nome) 将它们分行输出。
  • 您应该在程序结束时释放散列 table:
void Free_THT(THT *ht) {
    if (ht) {
        int i;
        for (i = 0; i < ht->nbuckets; i++) {
            TNode *list = ht->buckets[i];
            ht->buckets[i] = NULL;
            while (list != NULL) {
                TNode *node = list;
                list = list->next;
                free(node->name);
                free(node);
            }
        }
        free(ht->buckets);
        free(ht);
    }
}