【问题标题】:Proper Memory allocation正确的内存分配
【发布时间】:2026-02-18 13:50:01
【问题描述】:

我有以下结构:

typedef struct bucket {
    char *key;
    ENTRY *data;
    struct bucket *next;
} bucket;

typedef struct {
    size_t size;
    bucket **table;
} hash_table;

但我不知道如何为此分配内存。我试过了:

hash_table* ht = malloc(sizeof(hash_table)*101);

为了为 101 个条目创建一个哈希表,但它不起作用!谁能帮我?我真的很感激!

【问题讨论】:

  • 为什么是bucket **table,而不是bucket *table?

标签: c memory struct hashtable allocation


【解决方案1】:

hash_table 永远只有sizeof(hash_table) 字节大。 table 元素是指向bucket 元素的指针数组的指针。所以你需要这样的东西:

hash_table* ht = malloc(sizeof(hash_table));
ht->size = 101;
ht->table = malloc(sizeof(bucket*)*ht->size);

但我怀疑可能会附带一些初始化方法,然后您可以执行以下操作:

hash_table* ht = alloc_hash_table(101);

不管怎样,我对 C 语言有点生疏,所以对它持保留态度。

【讨论】:

  • 他有一个“bucket *table;”,即一个指向bucket的指针数组(可能是为了避免在需要之前分配bucket)。所以应该是“ht->table = malloc(sizeof(bucket)*ht->size);”
【解决方案2】:

不完全是。假设这是 C,你可能想要创建一个函数:

 hash_table* init_table(size_t size) {
     size_t i;
     hash_table* ht = (hash_table*)malloc(sizeof(hash_table));
     if (ht == NULL) return NULL;
     ht->size = size;
     ht->table = (bucket**)malloc(sizeof(bucket*)*size);
     if (ht->table == NULL) {
         free(ht);
         return NULL;
     }
     for (i = 0; i < size; ++i) {
         ht->table[i] = NULL;
     }
     return ht;
 }

您可能需要该结构中的一些其他字段。

如果您想变得狡猾,并且从不重新分配存储桶,您可以这样做:

 hash_table* init_table(size_t size) {
     hash_table* ht = (hash_table*)malloc(sizeof(hash_table)+sizeof(bucket)*size);
     if (ht == NULL) return NULL;
     ht->size = size;
     ht->table = (bucket**)(ht+1);
     for (i = 0; i < size; ++i) {
         ht->table[i] = NULL;
     }
     return ht;
 }

编辑:我将我的 bucket* 表固定到 bucket**

EDIT2:我已经摆脱了 memset 并为 malloc 添加了错误检查。

【讨论】:

  • 不会 "ht->bucket = (bucket*)(ht+1)" 只有在 "sizeof(size_t) == sizeof(void*)" 并且不需要内存分配时才有效(打包结构)?或者这是给定的?
  • ht+1 将您带到第一个 hash_table 之后的 hash_table,因此直接指向结构的最后一个字节之后的字节(+ 对齐目的所需的填充)。
  • 放松,你是对的。我没有注意到“表”是一个指针数组。
  • 你的“把戏”行不通。我强烈反对这样做。不能保证你有正确的对齐方式。而且,它应该是 malloc 调用中的 sizeof(bucket*)*size
  • 这仍然是坏的。 hash_table 结构的表成员是指向指针的指针,而不仅仅是一个指针。它应该只保存一个指向桶的指针数组,而不是桶本身。桶在插入时分配。代码没有意义。
【解决方案3】:

预先分配所有 101 个(或多个)存储桶是没有意义的,在向表中插入新数据时,您通常一次分配一个。

确实预先分配哈希数组是有意义的,它有一个固定的大小,但这是一个 桶指针数组,而不是桶数组,所以有些答案是错误的。

你有这样的东西,创建一个空的哈希表,有一个固定大小的桶数组:

hash_table * hash_table_new(size_t capacity)
{
  size_t i;

  hash_table *t = malloc(sizeof *t);
  t->size = capacity;
  t->bucket = malloc(t->size * sizeof *t->bucket);
  for(i = 0; i < t->size; i++)
    t->bucket[i] = NULL;
  return t;
}

这段代码:

  • 分配一个 hash_table 结构来保存表
  • 用指定的容量初始化它的大小
  • 分配适当长度的存储桶指针数组
  • 确保每个存储桶指针为 NULL(不能使用 memset() 正确完成,因为假设“所有位为零”是 NULL 在内存中的样子是不安全的)
  • 尽可能使用sizeof,但不在类型上,所以没有括号
  • 不强制转换 malloc() 的返回值,因为这在 C 中绝不是一个好主意
  • 不检查 malloc() 的返回值,当然你应该在实际代码中这样做

需要第二个函数来执行实际的哈希插入,然后需要分配一个新的存储桶,根据键计算哈希值,在哈希表的数组中选择正确的位置,然后在其中插入新条目.

【讨论】:

  • 我喜欢你如何使用表达式的大小,而不是类型。漂亮的风格。 +1
  • 这是使用 sizeof 的唯一方法。 :) 巨大的我最讨厌的东西,上面洒了水。
  • @unwind: 这么多好的做法(良好的 sizeof 使用,不强制转换 malloc,NULL/memset 陷阱)和结构良好的代码,但您不检查 malloc 的返回值?如果您不想通过错误处理使示例混乱,至少在您的列表中提及它应该在真实代码中执行。
  • 不过,我会使用 calloc 进行存储桶分配
【解决方案4】:

您的 typedef 有一些问题。假设您使用 MSVC。

在此处声明类型的一种简单方法是:

这个 typedef 包括 _type {} 类型,*ptype;同时声明类型和指向您的自定义类型的指针的格式。如果您在 hash_table 中看到向下,则可以使用 pbucket *table,它消除了代码中的额外 ***,并且可以在进行动态分配时提供帮助(帮助您保持头脑清醒,了解分配的内容等。 )。您的原始 typedef,如果您看起来有 typedef struct bucket {} bucket;,则在指定 typedef 时,您至少需要修改那里的两个“bucket”名称之一。

如果您使用 C++ 构建设置,您还需要进行转换,如果使用普通 C,您可能不需要转换,因此您的 malloc 行将是(我进行了以下 typedef 更改);

hash_table* ht = (phash_table) malloc(sizeof(hash_table)*101);

不管怎样,这个 sn-p 应该适合你;

typedef struct _bucket {    
    char *key;    
    void *data;    
    _bucket *next;
} bucket, *pbucket;

typedef struct _hash_table {    
    size_t size;    
    pbucket *table;
}hash_table, *phash_table;

【讨论】: