尽管我正确分配了指针段错误

时间:2019-03-08 17:38:06

标签: c pointers hash segmentation-fault malloc

我不明白为什么我的程序在以下行出现段错误:if ((**table->table).link == NULL){我似乎为它分配了malloc的内存,并尝试使用gdb进行查看。 *table->table可以访问并且不能为NULL,但是**table->table无法访问。 hash_t的定义:

struct table_s  {   
    struct node_s **table;
    size_t bins;    
    size_t size;
};

typedef struct table_s *hash_t;

void set(hash_t table, char *key, int value){
    unsigned int hashnum = hash(key)%table->bins;
    printf("%d \n", hashnum);
    unsigned int i;
    for (i = 0; i<hashnum; i++){
        (table->table)++;
    }
    if (*(table->table) == NULL){
        struct node_s n = {key, value, NULL};
        struct node_s *np = &n;
        *(table->table) = malloc(sizeof(struct node_s));
        *(table->table) = np;
    }else{
        while ( *(table->table) != NULL){
        if ((**table->table).link == NULL){
            struct node_s n = {key, value, NULL};
            struct node_s *np = &n;
            (**table->table).link = malloc(sizeof(struct node_s));
            (**table->table).link = np;
            break;
        }else if (strcmp((**table->table).key, key) == 0){
            break;
        }
            *table->table = (**(table->table)).link;
        }
        if (table->size/table->bins > 1){
            rehash(table);
        }
    }
}

我从这里打电话给我

  for (int i = 0; i < trials; i++) {
     int sample = rand() % max_num;
     sprintf(key, "%d", sample);
     set(table, key, sample);
  }

1 个答案:

答案 0 :(得分:0)

您的哈希表的工作方式如下:您有bins个bin,每个bin是键/值对的链接列表。箱中的所有项目均以箱数为模,共享相同的哈希码。

创建或初始化哈希表时,您可能已经创建了bins表,如下所示:

table->table = malloc(table->bins * sizeof(*table->table);

for (size_t i = 0; i < table->bins; i++) table->table[i] = NULL;

现在成员table为什么有两颗星?

  • “内部”星号表示表存储指向节点的指针,而不是节点本身。
  • “外部”开始是分配的内存的句柄。如果您的哈希表是固定大小的,例如始终具有256个bin,则可以将其定义为:

    struct node_s *table[256];
    

    如果您将此数组传递给周围,它将变成(或“衰减为”)指向其第一个元素struct node_s **的指针,就像从malloc获得的数组一样。

  • 您可以通过链接列表访问lbin的内容,链接列表的头itable->table[i]

您的代码还有其他问题:

  • 您想用(table->table)++实现什么?这将使分配的内存句柄不指向第一个元素,而是指向下一个元素。经过该哈希数次之后,*table->table现在将位于正确的节点上,但是您将丢失必须保留的原始句柄,因为在稍后清理时必须将其传递给free哈希表。不要丢失分配内存的句柄!改用另一个本地指针。

  • 您创建一个本地节点n,然后在链接列表中使用指向该节点的指针进行链接。但是,节点n将在您离开函数后消失,并且链接将“陈旧”:它将指向无效的内存。您还必须使用malloc为节点创建内存。

has表的简单实现可能是:

void set(hash_t table, char *key, int value)
{
    unsigned int hashnum = hash(key) % table->bins;

    // create (uninitialised) new node
    struct node_s *nnew = malloc(sizeof(*nnew));

    // initialise new node, point it to old head
    nnew->key = strdup(key);
    nnew->value = value;
    nnew->link = table->table[hashnum];

    // make the new node the new head
    table->table[hashnum] = nnew;
}

这使新节点成为链接列表的头部。这是不理想的,因为如果您覆盖项目,则会找到新项目(很好),但是旧项目仍将在表中(不好)。但是,正如他们所说,这是留给读者的练习。

strdup函数不是标准函数,但用途广泛。它还会创建新的内存,您必须稍后释放该内存,但可以确保在拥有字符串之后,字符串“ lives”(仍然有效)选择了哈希表。)

请不要在代码中有多少颗星星。如果一颗恒星太少,则位于hash_t中,在那里您已经抛弃了指针的性质。