C 什么';这个迷你HashMap有什么问题吗?

C 什么';这个迷你HashMap有什么问题吗?,c,hashmap,clang,C,Hashmap,Clang,我试图实现一个简单的HashMap,它只包含newget和insert功能。 有一个非常简单的测试函数,目前还没有通过 输出: 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&g

我试图实现一个简单的HashMap,它只包含
new
get
insert
功能。 有一个非常简单的测试函数,目前还没有通过

输出:

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;
}
#包括
#包括
#包括
#包括
#定义N(1000)
#定义乘数(37)
类型定义结构节点{
字符*键;
int值;
结构节点*下一步;
}节点;
typedef结构哈希映射{
节点*数据[N];
}哈希图;
无效试验();
无符号长散列(常量字符*键);
HashMap*新建_hash_map();
void insert_元素(char*键,int值,HashMap*hm);
int get_元素(char*key,HashMap*hm,int*el);
无符号长哈希(常量字符*s)
{
无符号长h;
无符号常量字符*us;
us=(无符号常量字符*)s;
h=0;
而(*us!='\0'){
h=h*乘数+us;
美国++;
}
返回h%N;
}
HashMap*新的\u哈希\u映射()
{
HashMap*hm=malloc(sizeof(HashMap));
对于(int i=0;idata[i]=NULL;
}
返回hm;
}
void insert_元素(char*键,int值,HashMap*hm)
{
无符号长hk=散列(键);
节点*ll=hm->data[hk];
如果(ll==NULL){
ll=malloc(sizeof(Node));
ll->key=key;
ll->value=value;
ll->next=NULL;
返回;
}
对于(;ll!=NULL;ll=ll->next){
如果(strcmp(ll->key,key)==0){
//已经存在
ll->value=value;
返回;
}
}
//新元素,相同的哈希键
ll->key=key;
ll->value=value;
ll->next=NULL;
}
int get_元素(char*键,HashMap*hm,int*el)
{
无符号长hk=散列(键);
节点*ll=hm->data[hk];
如果(ll==NULL){
返回-1;
}
对于(;ll!=NULL;ll=ll->next){
如果(strcmp(ll->key,key)==0){
//已经存在
*el=ll->value;
返回1;
}
}
返回-1;
}
无效测试()
{
HashMap*hm=新的_hash_map();
INTEL;
插入_元素(“aba”,10,hm);
插入_元素(“hhhh”,-10,hm);
获取元素(“hhh”、hm和el);
断言(el==-10);
获取元素(“aba”、hm和el);
断言(el==10);
}
int main(){
test();
返回0;
}

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

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

另外,第二个循环在这一点上也是相当误导的-您在
ll
中以
NULL
结束,然后取消引用它。你应该像以前一样分配和做同样的事情

   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中的一个插槽

一元*运算符表示间接。如果操作数指向 函数,结果是函数指示符;如果它指向一个 对象,结果是指定该对象的左值。如果操作数 具有类型“”指向类型“”的指针,结果具有类型“”类型“”如果是 为指针指定了无效值,该指针的行为 一元*运算符未定义

关于脚注

通过一元
*
运算符是空指针,该地址与 指向的对象的类型,以及 生命的尽头


主要的问题是,你从来没有插入过任何东西,你准备好了,分配了,然后分配给了合适的成员,然后你只是从函数返回

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

另外,第二个循环在这一点上也是相当误导的-您在
ll
中以
NULL
结束,然后取消引用它。你应该像以前一样分配和做同样的事情

   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中的一个插槽

一元*运算符表示间接。如果操作数指向 函数,结果是函数指示符;如果它指向一个 对象,结果是指定该对象的左值。如果操作数 具有类型“”指向类型“”的指针,结果具有类型“”类型“”如果是 为指针指定了无效值,该指针的行为 一元*运算符未定义

关于脚注

通过一元
*
运算符是空指针,该地址与 指向的对象的类型,以及 生命的尽头


... 并修复在冲突搜索耗尽时以空解引用结束的循环。@WhozCraig我不确定我是否遵循。你能详细解释一下吗?@Blas假设你修复了存储条目的代码。现在假设您在新插入时发生冲突,并确定键不匹配,您将遍历列表到最后,
ll
变为NULL,然后继续执行
ll->key=…
等,这是未定义的行为。@WhozCraig如果发生冲突,我将丢失进一步的分配,对吗?我不明白为什么我没有存储条目。不是
ll->value=value执行它?@Blas当代码尝试时
ll->value=value
ll
是空指针。。。。并修复在冲突搜索耗尽时以空解引用结束的循环。@WhozCraig我不确定我是否遵循。你能告诉我埃拉吗