[英]How to use pointers correctly in C
I am trying to add (key, value) pairs to a hashmap but cannot access the values after insertion. 我正在尝试将(键,值)对添加到哈希图中,但是在插入后无法访问这些值。
This hash table is supposed to deal with collisions as I am iterating along each hash index whenever a collision occurs. 每当发生冲突时,当我沿着每个哈希索引进行迭代时,此哈希表都应处理冲突。 I then insert it when I have reached the end of the (key, value) pair list at that index. 然后,在到达该索引的(键,值)对列表的末尾时,将其插入。
Essentially it is a basic linked list hashmap. 本质上,它是一个基本的链表哈希表。
The problem is, I keep getting a segmentation fault when I try to access the value again (and my showTable()
function also fails). 问题是,当我再次尝试访问该值时,我一直遇到分段错误(并且showTable()
函数也失败)。 In this test, I am simply trying to access the first (key, value) pair at each hash index after something is added at that hash index. 在此测试中,我只是在尝试在每个哈希索引处添加了一些东西之后,尝试访问每个哈希索引处的第一对(键,值)。 I am probably doing something very silly but I see it. 我做的事情可能很愚蠢,但我看到了。
I have not yet commented but I hope the code is self explanatory. 我尚未评论,但我希望代码能自我解释。 The important bit is InsertKeyValuePair()
but I have added everything as a code review would also be beneficial. 重要的一点是InsertKeyValuePair()
但是我添加了所有内容,因为代码审查也将是有益的。
#include <stdlib.h>
#include <stdio.h>
typedef struct TVal KeyValue;
typedef struct TVal {
char *value;
char *key;
KeyValue *next;
} KeyValue;
typedef KeyValue **HashTable;
int MAX_SIZE = 200;
int HashKey(char *Key, int Max);
void InsertKeyValuePair(char *key, char *value, int Index, HashTable table);
int insert(char *Key, char *value, HashTable table, int size);
void showTable(HashTable table, int size);
int HashKey(char *Key, int Max) {
char c = *Key;
int Hash = 0;
int n = 1;
while (c != 0) {
Hash += n * ((int)c);
c = *(Key + n);
n++;
}
return Hash % MAX_SIZE;
}
void InsertKeyValuePair(char *key, char *value, int Index, HashTable table) {
KeyValue *cursor = *(table + Index);
while (cursor != NULL) {
cursor = cursor->next;
}
cursor = malloc(sizeof(KeyValue));
cursor->value = value;
cursor->key = key;
printf("insert <K,V>(%s,%s) HashIndex = %i\n", cursor->key, cursor->value, Index);
//Trying to access value previously inserted
KeyValue *cursor2 = *(table + Index);
printf("<K,V>(%s,%s)\n", cursor2->key, cursor2->value);
}
int insert(char *Key, char *value, HashTable table, int size) {
int Index = HashKey(Key, MAX_SIZE);
InsertKeyValuePair(Key, value, Index, table);
return size + 1;
}
void showTable(HashTable table, int size) {
int i;
for (i = 0; i < size; i++) {
KeyValue *cursor = *(table + i);
if (cursor == NULL)
continue;
while (cursor != NULL) {
printf("==============");
printf("<K,V>(%s,%s)\n", cursor->key, cursor->value);
cursor = cursor->next;
}
printf("==============");
}
}
int main() {
HashTable HTbl = malloc(sizeof(HashTable) * MAX_SIZE);
int size = 0;
size = insert("yeuydfdan", "wesfg", HTbl, size);
size = insert("ywere", "rdgg", HTbl, size);
size = insert("ye4", "3244", HTbl, size);
//showTable(HTbl, MAX_SIZE);
}
This statement 这个说法
HashTable HTbl = malloc(sizeof(HashTable)*MAX_SIZE);
is incorrect and moreover the allocated memory is not initialized. 是不正确的,而且分配的内存没有初始化。 There should be 应该有
HashTable HTbl = calloc( MAX_SIZE, sizeof( KeyValue * ) );
or like 或喜欢
HashTable HTbl = calloc( MAX_SIZE, sizeof( *HTbl ) );
The index within the table should be calculated as some unsigned integer. 表中的索引应计算为一些无符号整数。 Otherwise in general you can get a negative index. 否则,通常可以得到一个负索引。
In function HashKey
parameter Max
is not used. 在函数HashKey
中,不使用Max
参数。
In the function InsertKeyValuePair
there is changed the local variable cursor
instead of the data member cursor->next
or *(table+Index)
. 在函数InsertKeyValuePair
,更改了局部变量cursor
而不是数据成员cursor->next
或*(table+Index)
。
The loop in the function showTable
shall use MAX_SIZE
not size
in the loop condition. 函数showTable
中的循环在循环条件下应使用MAX_SIZE
而不是size
。 That is you have to pass as an argument the value of MAX_SIZE
not the value of size
. 也就是说,您必须将MAX_SIZE
的值而不是size
的值作为参数传递。
Here is a demonstrative program that shows how the program can be updated. 这是一个演示程序,显示了如何更新程序。
#include <stdio.h>
#include <stdlib.h>
typedef struct TVal KeyValue;
typedef struct TVal
{
const char *value;
const char *key;
KeyValue *next;
} KeyValue;
typedef KeyValue **HashTable;
const size_t MAX_SIZE = 200;
static size_t HashKey( const char *key, size_t max_slots )
{
size_t Hash = 0;
for ( size_t i = 0; key[i]; i++ ) Hash += ( i + 1 ) * ( unsigned char )key[i];
return Hash % max_slots;
}
static int InsertKeyValuePair( HashTable table, const char *key, const char *value, size_t index )
{
KeyValue **cursor = &table[index];
while ( *cursor != NULL ) cursor = &( *cursor )->next;
*cursor = malloc( sizeof( KeyValue ) );
int success = *cursor != NULL;
if ( success )
{
( *cursor )->value = value;
( *cursor )->key = key;
( *cursor )->next = NULL;
}
return success;
}
int insert( HashTable table, const char *key, const char *value, size_t *size )
{
size_t index = HashKey( key, MAX_SIZE );
int success = InsertKeyValuePair( table, key, value, index );
if ( success ) ++*size;
return success;
}
void showTable( HashTable table, size_t size )
{
for ( size_t i = 0; i < size; i++ )
{
KeyValue *cursor = table[i];
if ( cursor != NULL )
{
do
{
puts( "==============" );
printf( "<K,V>(%s, %s)\n", cursor->key, cursor->value );
cursor = cursor->next;
} while ( cursor != NULL );
puts( "==============\n" );
}
}
}
int main( void )
{
HashTable HTbl = calloc( MAX_SIZE, sizeof( *HTbl ) );
size_t size = 0;
insert( HTbl, "yeuydfdan", "wesfg", &size );
insert( HTbl, "ywere", "rdgg", &size );
insert( HTbl, "ye4", "3244", &size );
showTable( HTbl, MAX_SIZE );
}
The program output is 程序输出为
==============
<K,V>(ywere, rdgg)
==============
==============
<K,V>(ye4, 3244)
==============
==============
<K,V>(yeuydfdan, wesfg)
==============
Of course you should add some other functions as for example a function that deletes the table with its nodes. 当然,您应该添加一些其他功能,例如删除表及其节点的功能。
And it will be better if each node will allocate memory for a key and a value and copy there the passed arguments. 如果每个节点都为一个键和一个值分配内存并在其中复制传递的参数,那将更好。 Otherwise the table may deal in general only with string literals because they have static storage duration. 否则,该表通常只能处理字符串文字,因为它们具有静态存储持续时间。
If you will rewrite the implementation of table such a way that it will copy keys and values in nodes of the table then the structure should be defined like 如果您将重写表的实现方式,使其复制表节点中的键和值,则结构应定义为
typedef struct TVal KeyValue;
typedef struct TVal
{
char *value;
const char *key;
KeyValue *next;
} KeyValue;
That is in any case the key should not be changed and should be declared with the qualifier const
. 也就是说,无论如何都不应该更改键,而应使用限定符const
对其进行声明。
There are multiple problems in your code: 您的代码中存在多个问题:
NULL
, causing segmentation faults when trying to dereference the pointers it contains. 哈希表未初始化为NULL
,从而在尝试取消对其包含的指针的引用时导致分段错误。 Allocating with calloc()
would fix this problem. 用calloc()
分配将解决此问题。 main
should read HashTable HTbl = calloc(sizeof(*HTbl), MAX_SIZE);
main
的分配应读取HashTable HTbl = calloc(sizeof(*HTbl), MAX_SIZE);
InsertKeyValuePair
does not link the new pair at the end, nor at the beginning of the hashtable bucket list. InsertKeyValuePair
中的插入代码不会在哈希表存储区列表的末尾或开头链接新对。 unsigned
arithmetics to compute the hash key to avoid overflow issues. 建议使用unsigned
算术来计算哈希键,以避免溢出问题。 *(table + Index)
is confusing. 指针符号*(table + Index)
令人困惑。 You should use the array notation table[Index]
instead. 您应该改用数组符号table[Index]
。 MAX_SIZE
) and the number of entries in the hashtable ( size
). 哈希表的长度( MAX_SIZE
)和哈希表中的条目数( size
)之间似乎有些混淆。 Renaming the variables appropriately may improve readability. 适当重命名变量可以提高可读性。 It is also probably better to pass the count by address and return a success indicator. 最好按地址传递计数并返回成功指示符。 Here is a corrected version: 这是更正的版本:
#include <stdlib.h>
#include <stdio.h>
typedef struct TVal KeyValue;
typedef struct TVal {
const char *value;
const char *key;
KeyValue *next;
} KeyValue;
typedef KeyValue **HashTable;
static unsigned int HASH_SIZE = 200;
static unsigned int HashKey(const char *key);
static KeyValue *InsertKeyValuePair(const char *key, const char *value, int index, HashTable table);
static int insert(const char *Key, const char *value, HashTable table, int *countp);
static void showTable(HashTable table);
static unsigned int HashKey(const char *key) {
unsigned int hash = 0;
size_t n;
for (n = 0; key[n] != 0; n++) {
hash += n * (unsigned char)key[n];
}
return hash % HASH_SIZE;
}
static KeyValue *InsertKeyValuePair(const char *key, const char *value, int index, HashTable table) {
KeyValue *cursor;
cursor = malloc(sizeof(KeyValue));
if (cursor != NULL) {
KeyValue **cursorp = &table[index];
while (*cursorp != NULL) {
cursorp = &(*cursorp)->next;
}
cursor->value = value;
cursor->key = key;
cursor->next = NULL;
*cursorp = cursor;
}
return cursor;
}
static int insert(const char *key, const char *value, HashTable table, int *countp) {
int index = HashKey(key);
if (InsertKeyValuePair(key, value, index, table)) {
*countp += 1;
return 1;
}
return 0;
}
static void showTable(HashTable table) {
unsigned int i;
for (i = 0; i < HASH_SIZE; i++) {
KeyValue *cursor = table[i];
if (cursor == NULL)
continue;
while (cursor != NULL) {
printf("==============");
printf("<K,V>(%s,%s)\n", cursor->key, cursor->value);
cursor = cursor->next;
}
printf("==============\n");
}
}
int main() {
HashTable HTbl = calloc(sizeof(*HTbl), HASH_SIZE);
int count = 0;
insert("yeuydfdan", "wesfg", HTbl, &count);
insert("ywere", "rdgg", HTbl, &count);
insert("ye4", "3244", HTbl, &count);
showTable(HTbl);
return 0;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.