C 什么';这个迷你HashMap有什么问题吗?
我试图实现一个简单的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
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
sdata
(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
sdata
(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我不确定我是否遵循。你能告诉我埃拉吗