【问题标题】:Segmentation fault when installing key value in hash table在哈希表中安装键值时出现分段错误
【发布时间】:2021-01-19 13:17:54
【问题描述】:

编辑:我已经更新了 init 函数(代码更新)以使用 malloc 并且分段错误消失了。但是我现在没有从打印表函数中得到任何输出。 根据建议进一步更新了代码。现在看来可以了。

我一直在关注 C 的 K&R(C 初学者),并尝试使用他们在第 6.7 节中的示例编写一个哈希表(几乎没有修改)

代码如下-

#include <stdio.h>
#include <string.h>
#include "hashtable.h"

#define HASHSIZE 101


listptr * init_table()
{
    listptr *hashtab = (listptr *) calloc(HASHSIZE, sizeof(*hashtab));
    return hashtab;
}

unsigned hash (char *s)
{
    unsigned hashval;

    for (hashval=0; *s != '\0'; s++)
        hashval = *s + 31 * hashval;

    return hashval % HASHSIZE;
}

listptr lookup (listptr * hashtab, char *s)
{
    listptr np;

    for (np = hashtab[hash(s)]; np!=NULL; np = np->next)
        if (strcmp(s, np->name) == 0)
            return np;
    return NULL;
}

listptr install(listptr * hashtab, char *name, char * defn)
{
    listptr np;

    unsigned hashval;

    if((np = lookup(hashtab, name)) == NULL) {
        np = (listptr) malloc(sizeof(*np));
        if (np==NULL || (np->name = strdup(name))==NULL)
            return NULL;

        hashval = hash(name);
        np->next = hashtab[hashval];
        hashtab[hashval] = np;
    }
    else
    {
        free((void*) np->defn);
    }
    if ((np->defn = strdup(defn)) == NULL)
        return NULL;

    return np;
}

void printtable(listptr * table, int len)
{
    listptr p;
    int i =0;
    while (i < len) {
        if (table[i] != NULL) {
            for (p = table[i];p!=NULL;p=p->next) {
                printf("%s\t%s\n", p->name, p->defn);
            }
        }
        i++;
    }
}

hashtable.h 包含 -

#ifndef HDR
#define HDR

#include <stdlib.h>

typedef struct nlist *listptr;

typedef struct nlist {
    listptr next;
    char *name;
    char *defn;
} Hashtablebucket;

listptr * init_table();
listptr lookup(listptr *, char *);
listptr install (listptr *, char *, char *);
void printtable(listptr *, int );

#endif

在 main.c 我有 -

#include <stdio.h>
#include <string.h>
#include "hashtable.h"

int main()
{
    listptr * table = init_table();


    install(table, "key1", "value1");
    install(table, "key2", "value2");
    install(table, "key3", "value3");

    printtable(table, 101);

    return 0;
}

这会导致分段错误,我不知道可能出了什么问题,因为哈希表有 101 个空间元素。

不胜感激调试问题的任何帮助...

编辑:上面的代码根本没有输出。有人可以帮忙调试吗?

提前致谢

【问题讨论】:

  • 没有检查其他部分,你的init_table是错误的,因为它返回的是一个非静态局部变量的地址,从函数返回时会失效,这个地址后面会用到。来自stdlib.hmalloc() 应该用于动态分配内存。
  • 你从哪里得到这个代码?我的 K&R 副本没有 init_table 函数...
  • 感谢 MikeCAT,我已经更新了 init_table 函数,现在它不再出现段错误。但是现在没有输出。你能帮忙看看剩下的代码吗?
  • 既然你找到了段错误的原因,你应该为新问题发布一个新问题。
  • Olaf 这是一个相关的问题...

标签: c segmentation-fault hashtable


【解决方案1】:

原始的 K&R 代码假定一个全局表。在您的情况下,您尝试在本地分配它,但您不能返回指向局部变量的指针(嗯,您可以,但行为未定义)。相反,您需要使用 malloc/ 或更好的分配内存,在这种情况下为 calloc

listptr * init_table()
{
    listptr *table = calloc(HASHSIZE, sizeof *table);
    return table;
}

最好为哈希表创建一个 struct,这样你就可以拥有不同大小的表:

struct hashtable {
    size_t n_slots;
    listptr *slots;
};

struct hashtable *init_table(size_t n_slots) {
    struct hashtable *tbl = malloc(sizeof *tbl);
    tbl->n_slots = n_slots;
    tbl->slots = calloc(n_slots, sizeof *(tbl->slots));
    return tbl;
}

对于hash 函数,最好保留它,以便它始终返回unsigned int(或size_t!),并在该函数之外进行取模。此外,char 可以签名或不签名;你很可能想使用unsigned chars。

size_t hash (char *s)
{
    size_t hashval;

    for (hashval=0; *s != '\0'; s++)
        hashval = *(unsigned char*)s + 31 * hashval;

    return hashval;
}

hashval = hash(name) % tbl->n_slots;

【讨论】:

  • 我已经接受了您的建议,即为不同大小的表使用哈希表本身的结构。您是否建议更改其他函数以接受 struct hashtable 作为参数,或者只是将 tbl->slots 传递给 install 等函数?
  • 还有如何修改hash函数来使用新的n_slots?
  • @g0d pointer 指向struct hashtable 作为参数,是的。至于hash()...
猜你喜欢
  • 2014-03-28
  • 2018-05-09
  • 1970-01-01
  • 2019-12-10
  • 2013-12-25
  • 2018-06-03
  • 2016-03-03
  • 2012-04-23
相关资源
最近更新 更多