这个迷你HashMap出了什么问题?

时间:2018-01-17 20:46:38

标签: c hashmap clang

我正在尝试实现一个只有new getinsert功能的简单HashMap。 有一个非常简单的测试功能,目前还没有通过。

输出:

test: Assertion `el == -10' failed.

调试测试时,我得到:

key: hhh value: 300
key: aba value: 300

什么时候应该:

key: hhh value: 10
key: aba value: -10

代码:

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

#include<assert.h>

#define N (1000)
#define MULTIPLIER (37)

typedef struct Node {
    char* key;
    int value;
    struct Node* next;
} Node;

typedef struct HashMap {
    Node* data[N];
} HashMap;

void test();

unsigned long hash(const char* key);
HashMap* new_hash_map();
void insert_element(char* key, int value, HashMap* hm);
int get_element(char* key, HashMap* hm, int* el);

unsigned long hash (const char* s)
{
    unsigned long h;
    unsigned const char* us;

    us = (unsigned const char*) s;

    h = 0;
    while (*us != '\0'){
    h = h * MULTIPLIER + *us;
    us++;
    }
    return h % N;
}

HashMap* new_hash_map()
{
    HashMap* hm = malloc(sizeof(HashMap));
    for (int i = 0; i < N; i++){
    hm->data[i] = NULL;
    }
    return hm;
}
void insert_element(char* key, int value, HashMap* hm)
{
    unsigned long hk = hash(key);
    Node* ll = hm->data[hk];
    if (ll == NULL) {
    ll = malloc(sizeof(Node));
    ll->key = key;
    ll->value = value;
    ll->next = NULL;
    return;
    }
    for (; ll != NULL; ll = ll->next){
    if (strcmp(ll->key, key) == 0){
        // already exists
        ll->value = value;
        return;
    }
    }
    // new element, same hash key
    ll->key = key;
    ll->value = value;
    ll->next = NULL;
}

int get_element(char* key, HashMap* hm, int* el)
{
    unsigned long hk = hash(key);
    Node* ll = hm->data[hk];
    if (ll == NULL) {
    return -1;
    }
    for (; ll != NULL; ll = ll->next){
    if (strcmp(ll->key, key) == 0){
        // already exists
        *el = ll->value;
        return 1;
    }
    }
    return -1;
}

void test()
{
    HashMap* hm = new_hash_map();
    int el;
    insert_element("aba", 10, hm);
    insert_element("hhhh", -10, hm);
    get_element("hhhh", hm, &el);
    assert(el == -10);
    get_element("aba", hm, &el);
    assert(el == 10);
}

int main () {
    test();
    return 0;
}

1 个答案:

答案 0 :(得分:2)

主要的问题是你从未插入任何东西,你已经准备好,分配然后分配给适当的成员,然后你只需从函数返回。

将分配的内存分配给hashmap s data。(hm->data[hk] = ll)。同时检查malloc的返回值。

此外,第二个循环非常具有误导性 - 您最终会在NULL中使用ll然后取消引用它。您应该分配并执行与之前相同的操作。

   for (; ll != NULL; ll = ll->next){
    if (strcmp(ll->key, key) == 0){
        // already exists
        ll->value = value;
        return;
    }
    }
    // if the ll is NULL (in case it doesn't match) 
    // the you wil dereference NULL leading to UB.
    // new element, same hash key
    ll->key = key;
    ll->value = value;
    ll->next = NULL;

取消引用NULL值是未定义的行为。这里可能的解决方案是为这个新节点分配内存,然后将其分配给hashmap中的一个插槽。

来自standard 6.5.3.2p4

  

一元*运算符表示间接。如果操作数指向a   功能,结果是功能指示符;如果它指向一个   对象,结果是指定对象的左值。如果是操作数   有类型&#39;&#39;指向类型&#39;&#39;,结果有类型&#39;&#39;类型&#39;&#39;。 如果是   无效值已分配给指针,行为   unary *运算符未定义

脚注

  

由一元*取消引用指针的无效值   operator是一个空指针,一个不恰当地对齐的地址   指向的对象类型,以及对象后面的地址   它的一生结束。