我正在尝试实现一个只有new
get
和insert
功能的简单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;
}
答案 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中的一个插槽。
一元*运算符表示间接。如果操作数指向a 功能,结果是功能指示符;如果它指向一个 对象,结果是指定对象的左值。如果是操作数 有类型&#39;&#39;指向类型&#39;&#39;,结果有类型&#39;&#39;类型&#39;&#39;。 如果是 无效值已分配给指针,行为 unary *运算符未定义。
脚注
由一元
*
取消引用指针的无效值 operator是一个空指针,一个不恰当地对齐的地址 指向的对象类型,以及对象后面的地址 它的一生结束。