【问题标题】:Hash Table Print "Stops Working"哈希表打印“停止工作”
【发布时间】:2014-01-03 07:32:23
【问题描述】:

作为练习(我是学生),我正在 C 中实现一个基本的 stringint 哈希表。我(我认为)一切正常,除了 print table function。它开始工作,但 Windows 在打印出一个存储桶的三个条目后说 “hashtable.exe 已停止工作”,我知道其他的都是有效的,因为我可以在命令提示符下检索它们的值我有的东西。这是我的代码,任何建议都很有价值:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

const char ESC_STRING[] = "zzzz";

struct a_container {
    char *string;
    int value; 
    struct a_container *next; 
};

typedef struct a_container Container;

struct c_list {
    Container **arr;
    int size;
    int bits;
}; 

typedef struct c_list Table;

void print_entry(Container *c) {
    printf("%s%s%d", c -> string, ", ", c -> value);
}

void print_table(Table *t) {
    Container *e;
    int i; 
    int length = t -> size;
    printf("%d\n", length);
    for(i = 0; i < length; i++) {
        printf("%d\n", i);
        if(t -> arr[i] == NULL) printf("%s\n", "Null bucket.");
        for(e = t -> arr[i]; e != NULL && e -> string != NULL; e = e -> next) {
            print_entry(e);
        }
    }
}

Container *make_cont() {
    Container *new;
    new = malloc(sizeof(Container));
    if(new == NULL) return NULL;

    new -> next = NULL;

    return new;
}

Container *make_entry(char *key, int value) {
    Container *n = make_cont();

    n -> string = key;
    n -> value = value;

    return n;
}

Table *make_table(int size) {
    Table *tab = NULL;
    int i; 
    int j = 2 << (size - 1);

    if(size < 1) return NULL;

    tab = malloc(sizeof(Table));
    tab -> arr = malloc(sizeof(Container) * j);

    for(i = 0; i < size; i++) {
        tab -> arr[i] = NULL;
    }

    tab -> size = j;
    tab -> bits = size;

    return tab;
}

void associate(Table *hashtable, char *key, int value) {
    int index = hash_index(hashtable, key, hashtable -> bits);
    Container *e = NULL;
    Container *n = NULL;

    if(hashtable -> arr[index] == NULL) {
        e = make_entry(key, value);
        hashtable -> arr[index] = e;
        return;
    }

    else {
        e = hashtable -> arr[index];
        n = make_entry(key, value);
        hashtable -> arr[index] = n;
        n -> next = e;
    }
}

int retrieve(Table *hashtable, char *look) {
    int index = hash_index(hashtable, look, hashtable -> bits);
    Container *e = NULL;

    //if(hashtable -> arr[index] == NULL) exit(1);

    e = hashtable -> arr[index];
    while(e != NULL && e -> string != NULL && strcmp(look, e -> string) > 0) {
        e = e -> next; 
    }

    if(e == NULL || e -> string == NULL || strcmp(look, e -> string) != 0) {
        exit(1);
    } else {
        return e -> value; 
    }
}

//djb2 algorithm by dan bernstein
//http://www.cse.yorku.ca/~oz/hash.html
unsigned long hash_code(char *key) {
    unsigned long hash = 5381;
    int c; 

    while(c = *key++) {
        hash = ((hash << 5) + hash) + c;
    }

    return hash; 
}

int hash_index(Table *hashtable, char *query, int bits) {
    unsigned long hashCode = hash_code(query);
    unsigned int fold = 0; 
    unsigned int h; 
    int trim = 2 << (bits - 1);
    int mask = trim - 1;

    for(h = hashCode; h != 0; h >>= bits) {
        fold ^= h;
    }

    fold &= mask;
    return fold; 
}

int main() {
    char *i; 
    Table *hashtable = make_table(3);

    associate(hashtable, "Erica", 323);
    associate(hashtable, "Kitty", 18);
    associate(hashtable, "Dawg", 3);
    associate(hashtable, "Dahhhhhhg", 43);
    associate(hashtable, "Kat", 7);

    //print_table(hashtable);

    while(1) {
        printf("%s", "Look something up: ");
        scanf("%s", i);
        if(strcmp(i, ESC_STRING) == 0) break;
        printf("%d\n", retrieve(hashtable, i)); 
    }

    return 0; 
}

【问题讨论】:

  • 你为什么用Container **arr而不是Container *arr
  • 请学习调试 -- 使用调试器和/或诊断 printfs。 SO 不能替代它。

标签: c hashtable


【解决方案1】:

在为变量赋值之前,您不能使用变量的值。在main 中,您将i 的值传递给scanf,但尚未为其分配值。所以你给scanf 传递了一个垃圾地址,当scanf 试图在那个无意义的位置存储一些东西时,它会导致程序崩溃。

【讨论】:

  • 这不是崩溃的原因 - 它是 print_table。我那愚蠢的小无限循环查询工作正常。
  • @AdamR。当您有未定义的行为时,其他人无法判断它对您的失败程度。
【解决方案2】:

奇怪的是,您的程序在我的系统上按原样编译和运行,甚至print_table() 函数、查找...对我来说都运行良好。也就是说,您应该修复 Adam 指出的错误:将输入字符串存储在未定义的地址是一个严重的错误。

仅仅声明char *i; 将导致i 包含一个地址,该地址等于该位置执行堆栈上的最后一个地址。换句话说,它可以是任何东西。因此,该程序实际上有时可能在某些计算机上运行,​​有时则不能,这取决于i 是否恰好包含有效地址。这或许可以解释为什么您的程序在我的计算机上按原样运行,而在您的计算机上却不能。

你可以写:

char i[128];

...和...

scanf("%s", i);

【讨论】:

  • 它适用于我在 GCC 下的 Linux 分区。所以我应该把这归结为 VS2013 很奇怪吗?
  • @AdamR。不,你应该考虑到你有不可移植的代码和未定义的行为,并使用VS的调试功能来追踪错误。
【解决方案3】:

这是可以解释问题的修改代码(来自函数print_table):

if ( t->arr[i] == NULL ) printf("%s\n", "Null bucket.");
// what happens when t->arr[i] == NULL ?
// e->string is a NULL pointer deference.
for ( e = t->arr[i]; e != NULL && e->string != NULL; e = e->next ) {
    print_entry(e);
}

修复:

if ( t->arr[i] == NULL )
    printf("%s\n", "Null bucket.");    
else
    for ( e = t->arr[i]; e != NULL && e->string != NULL; e = e->next ) {
        print_entry(e);
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-16
    • 2013-04-18
    • 2014-11-30
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多