值被覆盖的哈希表问题

Posted

技术标签:

【中文标题】值被覆盖的哈希表问题【英文标题】:Hash table problems with values getting overwritten 【发布时间】:2020-07-25 04:57:58 【问题描述】:

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

这是我的代码:

#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-&gt;buckets 的值,内部发生了一些变化。

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

【问题讨论】:

【参考方案1】:

不相关,但使用英文名称和输出会使每个人都更容易。


只是猜测,但在 Create_Node 内部,您为新节点分配内存,但不为名称 (nome) 分配内存。

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

node->nome = strdup(nome);

别忘了,当你在更大的上下文中使用散列时,你最终必须清理散列和名称,这意味着为节点和名称释放内存

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

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

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

【讨论】:

我应该为那个函数包含什么库?? 我应该在代码的哪一部分为节点->名称和节点本身释放内存? 你有Create_* 函数,你需要Destroy_* 函数来清理散列结构。当您不再需要哈希时,您需要这些函数。 我做了你建议的更正,程序做了它应该做的。我不知道我是否理解问题所在,但是使用旧代码运行调试(也许)我发现当我使用 node->name =name 初始化节点时,它获取了字符串第一个字符的地址我通过输入插入的名称对于下一个插入没有改变。所以它覆盖了所有其他名字的插入。如果我错了,请纠正我【参考方案2】:

你的代码有很多问题:

您将指针隐藏在 typedef TNode *TList; 中的 typedef 后面,这很容易出错,并且会让您的代码的读者感到困惑。 CreateNode 不会复制name 指向的内存。鉴于您如何使用此函数,所有节点共享同一个数组,因此所有节点都具有相同的名称。使用node-&gt;nome = strdup(nome); 来解决这个问题。 scanf("%s", &amp;name); 不正确:&amp; 是多余的,您应该指定要存储到 name 的最大字符数以避免缓冲区溢出。使用scanf("%39s", name);。此外,您应该测试返回值以检测文件意外结束。 Print_List 不分隔名称。使用printf("%s\n", list-&gt;nome) 将它们输出到不同的行。 您应该在程序结束时释放哈希表:
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);
    

【讨论】:

第二点是我需要的,我没有优化就编写了代码,我知道其他错误,但我只是想解决覆盖问题。谢谢回答

以上是关于值被覆盖的哈希表问题的主要内容,如果未能解决你的问题,请参考以下文章

哈希表/散列表

为啥哈希表在存储桶的数组上使用链表?

在 PowerShell 中合并哈希表:如何?

redis hset 哈希表存储问题

哈希表(JavaScript实现)

redis hset 和hsetnx 的区别是啥