【问题标题】:Memory allocation problem in HashTableHashTable中的内存分配问题
【发布时间】:2010-10-24 02:35:59
【问题描述】:

请不要以duplicate question 结尾。我做了一个重要的更改,以免混淆,我重新提交了更清晰的代码。

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

ma​​in.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->list。在上面的例子中,我的尝试是让它成为一个包含 10 个列表的数组。

请帮我解决这个问题。

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

【问题讨论】:

    标签: c memory memory-management


    【解决方案1】:

    这一行

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

    应该阅读

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

    我还建议您遵循上一篇文章中给您的建议,不要通过 typedef'ing 隐藏指针。只需使用List *

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

    【讨论】:

    • 我了解 Mitch,但问题是我从教授那里得到了 List.h 和 List.c 文件,无法解决这个问题。我尝试将 HashTablePtr 转换为 HashTable 但没有任何运气。
    • 那么我会(在获得你的作业分数后!)建议“教授”(匿名?)不要混淆他的学生并遵循行业最佳实践。
    • 我们已经在课堂上讨论过这个问题,教授说“这就是我学习 C 的方式,这是很好的做法。对我来说,代码更干净,因为我不必处理一堆星号。”
    • 或者干脆忽略 typedef 并使用 List *。它们是等价的,所以它仍然适用于教授的代码。
    • @newbie:您的教授可能从未编写过或必须维护生产代码。
    【解决方案2】:

    您也可以使用一个很好的成语,例如:

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

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

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

    【讨论】:

    • +1 让我不必发布关于使用 sizeof 的说明。此外,IMO malloc() 的返回值永远不应该在 C 中强制转换,它只是没有意义和愚蠢。
    • 没错,但据我们所知,他的教授让他在 C++ 编译器中编写 C 代码,所以我把它留在了那里。
    【解决方案3】:

    在这一行:

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

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

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

    编辑

    正如 leiz 和 Klathzazt 在 cmets 中指出的,Hashtable.list 类型是 ListPtr*List**

    struct hashtable {
        ...
        ListPtr *list;
    

    这就是为什么尝试分配从calloc 返回和强制转换的ListPtr 类型会导致编译器错误的原因。与其在Hashtable 中存储指向列表指针的指针,不如只保存指向列表的指针:

    struct hashtable {
        ...
        ListPtr list;
    

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

    【讨论】:

    • 如果我尝试将 ListPtr * 替换为 ListPtr: HashTable.c:15: 警告:来自不兼容指针类型的赋值
    • 你的哈希表“ListPtr *list;”也应该是“ListPtr list”
    • 在你的结构中也是如此——你必须用 ListPtr 替换 ListPtr *。如前所述,如果您没有 typedef 语句,那么混乱会少很多。
    • 好吧,这似乎让它变得更好了,但是我怎样才能制作一个包含 10 个列表的数组?
    【解决方案4】:

    就我个人而言,我不是很喜欢使用 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);
    

    【讨论】:

    • 您应该指出您指的是 C99 标准的哪个部分。这是一个很大的文件。
    • 我指的不是特定的部分,只是说它是一份值得拥有和阅读的好文档。
    猜你喜欢
    • 2011-01-07
    • 2011-03-18
    • 1970-01-01
    • 2021-05-04
    • 2021-06-30
    • 2011-05-17
    相关资源
    最近更新 更多