У меня есть такая конструкция:
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 запись, но это не работает! Может кто-нибудь мне помочь? Я был бы очень признателен!





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, так что относитесь к этому с недоверием.
У него есть "ведро * table; ", то есть массив указателей на сегменты (вероятно, чтобы не выделять сегменты до тех пор, пока они не понадобятся). Таким образом, он должен быть" ht-> table = malloc (sizeof (bucket) * ht-> size);"
Не совсем. Предполагая, что это 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;
}
Обновлено: я установил свой стол из ведра * в ведро **
EDIT2: я избавился от наборов памяти и добавил проверку ошибок для malloc.
Разве «ht-> bucket = (bucket *) (ht + 1)» не будет работать только тогда, когда «sizeof (size_t) == sizeof (void *)» и не требуется выравнивание памяти (упакованная структура)? Или это данность?
ht + 1 переносит вас в hash_table после первой hash_table и, таким образом, указывает на байт непосредственно после последних байтов структуры (+ заполнение, необходимое для выравнивания).
расслабься, ты прав. Я не заметил, что «таблица» была массивом указателей.
ваш "трюк" не сработает. я бы категорически отговаривал от этого. нет никакой гарантии, что у вас правильное выравнивание. а также должно быть sizeof (bucket *) * size в вызове malloc
Это все еще не работает. Член таблицы структуры hash_table является указателем на указатель, а не просто указателем. Предполагается, что он просто содержит массив указателей на сегменты, а НЕ сами сегменты. Ковши расположены на вставке. Код не имеет смысла.
Есть множество проблем с этим ответом: от приведения malloc до неправильного использования memset до того, что он просто не работает. Пожалуйста, примите ответ @ unwind или, по крайней мере, не принимайте этот ответ.
Расслабьтесь и ltib: это sizeof (bucket *) * size в вызове malloc. Роберт: что не так с memset?
ht + 1 должен иметь правильное выравнивание. Он идентичен & ht [1]. Я скомпилировал и запустил этот код в Visual Studio. Работает отлично и без предупреждений.
Вы используете memset для инициализации значений указателя, предполагая, что представление для нулевого указателя является нулевым по всем битам, что не гарантируется.
Предоставляется. Я никогда не работал над архитектурой со странными указателями. Так как еще проверено, исправлю.
Нет смысла выделять все 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;
}
Этот код:
sizeof, но не для типов, поэтому без скобокmalloc(), так как это никогда не бывает хорошей идеей в CВторая функция потребуется для выполнения фактической вставки хэша, которая затем должна будет выделить новое ведро, вычислить хеш-значение из ключа, выбрать правильное место в массиве хеш-таблицы и вставить туда новую запись.
Мне нравится, как вы берете размер выражений, а не тип. хороший стиль. +1
Это единственный способ использовать sizeof. :) Огромный моя любимая мозоль, с брызгами сверху.
@unwind: Так много хороших практик (хорошее использование sizeof, без приведения malloc, ловушка NULL / memset) и хорошо структурированный код, но вы не проверяете возвращаемое значение malloc? Если вы не хотите загромождать пример обработкой ошибок, хотя бы упомяните в своем списке, что это должно выполняться в реальном коде.
Я бы использовал calloc для распределения корзины, хотя
Есть кое-что, что нужно сделать для вашего typedef. Предполагая, что вы используете MSVC.
Простой способ объявить здесь типы:
Этот typedef включает тип _type {}, * ptype; формат, который объявляет тип и указатель на ваш настраиваемый тип одновременно. Если вы видите вниз в hash_table, вы можете использовать таблицу pbucket *, которая устраняет лишние *** в вашем коде и может помочь при динамическом распределении (помогите так mucah, чтобы держать голову прямо о том, что вы распределяете и т. д. ). Ваш исходный typedef, если вы посмотрите, имеет typedef struct bucket {} bucket ;, вам нужно по крайней мере изменить одно из двух имен "bucket", которые у вас есть там, когда вы указываете свой typedef.
Вам также необходимо выполнить приведение, если вы используете настройки сборки C++, при использовании простого C вам может не понадобиться приведение, поэтому ваша строка malloc будет (со следующими изменениями typedef, которые я сделал);
hash_table* ht = (phash_table) malloc(sizeof(hash_table)*101);
В любом случае этот фрагмент должен сработать для вас;
typedef struct _bucket {
char *key;
void *data;
_bucket *next;
} bucket, *pbucket;
typedef struct _hash_table {
size_t size;
pbucket *table;
}hash_table, *phash_table;
почему таблица bucket **, а не таблица bucket *?