HashTable中的内存分配问题

时间:2009-05-06 05:12:39

标签: c memory memory-management

请不要将此duplicate question关闭。我做了一个重要的改变,所以不要混淆别人,我重新提交了这个更清晰的代码。

请帮我解决这个内存分配问题。我正在研究HashTable,这就是我(仅部分代码)

的main.c

HashTablePtr hash;
hash = createHashTable(10);
insert(hash, "hello");
insert(hash, "world");

HashTable.c

    HashTablePtr createHashTable(unsigned int capacity){
    HashTablePtr hash;
    hash = (HashTablePtr) malloc(sizeof(HashTablePtr));
    hash->size = 0;
    hash->capacity = capacity;          
    hash->list = (ListPtr *)calloc(capacity, sizeof(List)); /*NO MEMORY ALLOCATION HERE*/
    return hash;

List.h

typedef struct list List;
typedef struct list * ListPtr;

struct list {
    int size;
    NodePtr head;
    NodePtr tail;
};
...
...

HashTable.h

    typedef struct hashtable * HashTablePtr;
    typedef struct hashtable HashTable;
    struct hashtable {
        unsigned int capacity;
        unsigned int size;
        ListPtr *list;
        unsigned int (*makeHash)(unsigned int, void *);
    };
...
...

当我运行我的调试器(Netbeans C / C ++调试器时,我发现没有内存被分配给hash->列表。在上面的例子中,我的尝试是使它成为10个列表的数组。

请帮我解决这个问题。

如果有帮助的话,我不是C的专家。

4 个答案:

答案 0 :(得分:4)

这一行

hash = (HashTablePtr) malloc(sizeof(HashTablePtr));

应该阅读

hash = (HashTablePtr) malloc(sizeof(HashTable));

我还建议您按照上一篇文章中给出的建议,而不是通过typedef'ing隐藏指针。只需使用List *

即可

[每当你看到一个alloc语句时,你指定的类型是一个指针,你要分配的类型应该是类型(而不是指向该类型的指针)]

答案 1 :(得分:4)

你可以使用的一个很好的习语是:

hash = (HashTablePtr) malloc(sizeof(*hash));

通过不对分配中的任何类型进行硬编码,大大减少了混合的可能性。

请注意,'hash'实际上并未在此处取消引用 - sizeof()始终在编译时进行评估,因此编译器只需计算出* hash / will / have的类型,并获取其大小。

答案 2 :(得分:1)

在这一行:

hash->list = (ListPtr *)calloc(capacity, sizeof(List));

calloc函数将为List分配一些内存,然后返回指向已分配内存的指针,该内存为List*(或相当于ListPtr,因为typedef。)

在代码中,指针随后被转换为(ListPtr*),其实际上是List**,而不是预期的类型List*。因此,请将ListPtr*更改为ListPtr并查看是否可以修复该行。

修改

正如leiz和Klathzazt在评论中指出的那样,Hashtable.list类型为ListPtr*List**

struct hashtable {
    ...
    ListPtr *list;

这就是为什么尝试分配从ListPtr返回并转换的calloc类型会导致编译器错误的原因。它不是存储指向Hashtable中List的指针的指针,而应该只保存指向列表的指针:

struct hashtable {
    ...
    ListPtr list;

这应该消除编译器错误,因为Hashtable.list和类型转换的类型都是ListPtr

答案 3 :(得分:0)

就我个人而言,我并不是使用typedef的忠实粉丝,特别是当你是初学者时。我认为这可能部分令你感到困惑。你最好避免这样的事情:

typedef struct hashtable * HashTablePtr;

使用许多typedef会使你的代码更难阅读,因为你需要经常查找他们所指的内容。

主要问题是您为哈希表/列表指针的大小分配内存,而不是为其受尊重的结构的大小分配内存。我认为下面的代码很好地说明了这一点。您还需要检查分配是否有效。如果是malloc,calloc,realloc。等失败,他们返回NULL。如果发生这种情况并且您没有检查此情况,则会出现段错误,程序将崩溃。

同样遵循c99标准,并将所有变量声明放在函数的开头。

c99 std

malloc manpage

struct hashtable *
createHashTable(unsigned int capacity){
    struct hashtable *hash;
    struct list *mylist;

    /* You want to allocate size of the hash structure not the size of a pointer. */
    hash = malloc(sizeof(struct hashtable)); 
    // always make sure if the allocation worked.
    if(hash == NULL){
        fprintf(stderr, "Could not allocate hashtable\n");
        return NULL;
    }

    hash->size = 0;
    hash->capacity = capacity;

    /* Unless you need the memory to be zero'd I would just use malloc here
     * mylist = calloc(capacity, sizeof(struct list)); */
    mylist = malloc(capacity * sizeof(struct list));
    if(mylist == NULL){
        fprintf(stderr, "Could not allocate list\n");
        free(hash); /* free our memory and handle the error*/
        return NULL;
    }

    mylist->head = NULL;
    mylist->size = 0;
    mylist->tail = NULL;    
    hash->list = mylist;

    return hash;
}

还要记得在释放哈希表之前释放你的名单:

free(myhash->list);
free(myhash);