繁体   English   中英

如何在C中正确使用指针

[英]How to use pointers correctly in C

我正在尝试将(键,值)对添加到哈希图中,但是在插入后无法访问这些值。

每当发生冲突时,当我沿着每个哈希索引进行迭代时,此哈希表都应处理冲突。 然后,在到达该索引的(键,值)对列表的末尾时,将其插入。

本质上,它是一个基本的链表哈希表。

问题是,当我再次尝试访问该值时,我一直遇到分段错误(并且showTable()函数也失败)。 在此测试中,我只是在尝试在每个哈希索引处添加了一些东西之后,尝试访问每个哈希索引处的第一对(键,值)。 我做的事情可能很愚蠢,但我看到了。

我尚未评论,但我希望代码能自我解释。 重要的一点是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);
}

这个说法

HashTable HTbl = malloc(sizeof(HashTable)*MAX_SIZE);

是不正确的,而且分配的内存没有初始化。 应该有

HashTable HTbl = calloc( MAX_SIZE, sizeof( KeyValue * ) );

或喜欢

HashTable HTbl = calloc( MAX_SIZE, sizeof( *HTbl ) );

表中的索引应计算为一些无符号整数。 否则,通常可以得到一个负索引。

在函数HashKey中,不使用Max参数。

在函数InsertKeyValuePair ,更改了局部变量cursor而不是数据成员cursor->next*(table+Index)

函数showTable中的循环在循环条件下应使用MAX_SIZE而不是size 也就是说,您必须将MAX_SIZE的值而不是size的值作为参数传递。

这是一个演示程序,显示了如何更新程序。

#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 );
}

程序输出为

==============
<K,V>(ywere, rdgg)
==============

==============
<K,V>(ye4, 3244)
==============

==============
<K,V>(yeuydfdan, wesfg)
==============

当然,您应该添加一些其他功能,例如删除表及其节点的功能。

如果每个节点都为一个键和一个值分配内存并在其中复制传递的参数,那将更好。 否则,该表通常只能处理字符串文字,因为它们具有静态存储持续时间。

如果您将重写表的实现方式,使其复制表节点中的键和值,则结构应定义为

typedef struct TVal KeyValue;

typedef struct TVal 
{
    char *value;
    const char *key;
    KeyValue *next;
} KeyValue;

也就是说,无论如何都不应该更改键,而应使用限定符const对其进行声明。

您的代码中存在多个问题:

  • 哈希表未初始化为NULL ,从而在尝试取消对其包含的指针的引用时导致分段错误。 calloc()分配将解决此问题。
  • 将指针隐藏在typedef后面会造成混淆,并且容易出错。
  • main的分配应读取HashTable HTbl = calloc(sizeof(*HTbl), MAX_SIZE);
  • InsertKeyValuePair中的插入代码不会在哈希表存储区列表的末尾或开头链接新对。
  • 建议使用unsigned算术来计算哈希键,以避免溢出问题。
  • 指针符号*(table + Index)令人困惑。 您应该改用数组符号table[Index]
  • 哈希表的长度( MAX_SIZE )和哈希表中的条目数( size )之间似乎有些混淆。 适当重命名变量可以提高可读性。 最好按地址传递计数并返回成功指示符。

这是更正的版本:

#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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM