Правильное распределение памяти

У меня есть такая конструкция:

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 **, а не таблица bucket *?

ysth 16.12.2008 12:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
944
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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);"

atzz 16.12.2008 11:55
Ответ принят как подходящий

Не совсем. Предполагая, что это 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 *)» и не требуется выравнивание памяти (упакованная структура)? Или это данность?

Joachim Sauer 16.12.2008 11:59

ht + 1 переносит вас в hash_table после первой hash_table и, таким образом, указывает на байт непосредственно после последних байтов структуры (+ заполнение, необходимое для выравнивания).

jmucchiello 16.12.2008 12:02

расслабься, ты прав. Я не заметил, что «таблица» была массивом указателей.

jmucchiello 16.12.2008 12:08

ваш "трюк" не сработает. я бы категорически отговаривал от этого. нет никакой гарантии, что у вас правильное выравнивание. а также должно быть sizeof (bucket *) * size в вызове malloc

Johannes Schaub - litb 16.12.2008 13:40

Это все еще не работает. Член таблицы структуры hash_table является указателем на указатель, а не просто указателем. Предполагается, что он просто содержит массив указателей на сегменты, а НЕ сами сегменты. Ковши расположены на вставке. Код не имеет смысла.

unwind 16.12.2008 15:52

Есть множество проблем с этим ответом: от приведения malloc до неправильного использования memset до того, что он просто не работает. Пожалуйста, примите ответ @ unwind или, по крайней мере, не принимайте этот ответ.

Robert Gamble 16.12.2008 16:02

Расслабьтесь и ltib: это sizeof (bucket *) * size в вызове malloc. Роберт: что не так с memset?

jmucchiello 16.12.2008 21:42

ht + 1 должен иметь правильное выравнивание. Он идентичен & ht [1]. Я скомпилировал и запустил этот код в Visual Studio. Работает отлично и без предупреждений.

jmucchiello 16.12.2008 21:48

Вы используете memset для инициализации значений указателя, предполагая, что представление для нулевого указателя является нулевым по всем битам, что не гарантируется.

Robert Gamble 16.12.2008 23:16

Предоставляется. Я никогда не работал над архитектурой со странными указателями. Так как еще проверено, исправлю.

jmucchiello 16.12.2008 23:24

Нет смысла выделять все 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

Johannes Schaub - litb 16.12.2008 13:43

Это единственный способ использовать sizeof. :) Огромный моя любимая мозоль, с брызгами сверху.

unwind 16.12.2008 15:53

@unwind: Так много хороших практик (хорошее использование sizeof, без приведения malloc, ловушка NULL / memset) и хорошо структурированный код, но вы не проверяете возвращаемое значение malloc? Если вы не хотите загромождать пример обработкой ошибок, хотя бы упомяните в своем списке, что это должно выполняться в реальном коде.

Robert Gamble 16.12.2008 15:56

Я бы использовал calloc для распределения корзины, хотя

Hasturkun 13.01.2009 16:51

Есть кое-что, что нужно сделать для вашего 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;

Другие вопросы по теме