How to initialize a hashmap in c? - c

I need to initialize a hashmap in C. I have created structs for hashnode and hashmap which will be shown below, but I need to send it to a function
void hashmap_init(hashmap_t *hm, int table_size);
and I need to initialize the hash map 'hm' to have given size and item_count 0. Have to ensure that the 'table' field is initialized to an array of size 'table_size' and filled with NULLs.
typedef struct hashnode {
char key[128];
char val[128];
struct hashnode *next;
} hashnode_t;
typedef struct {
int item_count;
int table_size;
hashnode_t **table;
} hashmap_t;
#define HASHMAP_DEFAULT_TABLE_SIZE 5

Use malloc() to allocate an array of table_size buckets.
void hashmap_init(hashmap_t *hm, int table_size) {
hm->item_count = 0;
hm->table_size = table_size;
hm->table = malloc(table_size * sizeof *(hm->table));
for (int i = 0; i < table_size; i++) {
hm->table[i] = NULL;
}
}
If you need to remove the hash map, you reverse the allocations:
for (int i = 0; i < hm->table_size; i++) {
free(hm->table[i]);
}
free(hm->table);

Related

How do I iterate through an array of structs?

I have this hashmap I want to implement.
typedef void * Data;
typedef struct {
Data data; //Data pointer to the data
char * key; //char pointer to the string key
} HashMapItem;
typedef struct hashmap {
HashMapItem * items; //items of the hashmaps
size_t size; //size of the hashmaps
int count; //how many elements are in the hashmap
} HashMap;
I declare it like so:
HashMap * create_hashmap(size_t key_space){
if(key_space == 0)
return NULL;
HashMap * hm = malloc(sizeof(HashMap)); //allocate memory to store hashmap
hm->items = calloc(key_space, sizeof(HashMapItem)); //allocate memory to store every item inside the map, null it
hm->size = key_space; //set sitze of hashmap
hm->count = 0; //empty at the begining
return hm;
}
When i try to iterate through it, it says that
expression must have arithmetic or pointer type but has type "HashMapItem" even though i declare it as a pointer of HashMapItems
if((hm->items)[index] != NULL)
Any idea?
typedef void * Data;
Never hide pointers behind typedefs. It is a very, very bad practice.
How to iterate.
typedef struct {
void *data; //Data pointer to the data
char * key; //char pointer to the string key
} HashMapItem;
typedef struct hashmap {
HashMapItem * items; //items of the hashmaps
size_t size; //size of the hashmaps
size_t count; //how many elements are in the hashmap
} HashMap;
void foo(HashMap *map)
{
for(size_t i = 0; i < map -> count; i ++)
{
puts(map -> items[i].key);
}
}
PS count member should be also size_t
EDIT. Below is wrong as hm->items)[index] has type HashMapItem and it is not pointer. You cant compare it to NULL.
if((hm->items)[index] != NULL)

When resizing a hash table how to point to the new array of buckets

When testing my code it seems as though when I am resizing my bucket array the hash_table struct is not pointing to my new resized hash table. Is this the route to take when resizing a hash table? Or instead of having buck_array being hash_entry ** should it have been a hash_entry *
also hash_key() function gives the index in the bucket array based on char *string.
relevant structs:
typedef struct hash_entry_{
char *string;
void *data;
struct hash_entry_ *next;
}hash_entry;
typedef struct hash_table_{
hash_entry ** buck_array;
unsigned num_buckets;
} hash_table, *Ptrhash_table;
My resize function:
void resize_hash(Ptrhash_table table, int size) {
unsigned int old_Bnum = table->num_buckets;
table->num_buckets = size;
int i;
hash_entry *cur;
hash_entry **new_arr = (hash_entry **)calloc(size, sizeof(hash_entry));
for (i = 0; i < size; i++){
new_arr[i] = NULL;
}
for (i = 0; i <= old_Bnum; i++) {
while((table->buck_array[i]) != NULL){
cur = table->buck_array[i];
table->buck_array[i] = cur->next;
cur->next = new_arr[hash_key(table, cur->string)];
new_arr[hash_key(table, cur->string)] = cur;
}
}
free(table->buck_array);
table->buck_array = new_arr;
}

Hash table init_hash in c

I need to initialized the hash table with the size i get, i have a problem here t->arr_table[i]->key = NULL;
#include <stdio.h>
typedef struct element{
char * key;
char * value;
}element;
typedef struct HashTable{
int size; // size of the arr
element **arr_table; //arr of elements
}HashTable;
void init_hash(int size, HashTable * t)
{
if (size < 1)
return;
t->size = size;
t->arr_table = (element **)malloc(sizeof(element*)*size);
if (t->arr_table == NULL) // out memory
return;
int i;
for (i = 0; i < size; i++)
{ // initial list
t->arr_table[i]->key = NULL;
t->arr_table[i]->value = NULL;
}
}
void main()
{
HashTable *ht = (HashTable*)malloc(1*sizeof(HashTable));
int size_ht = 9;
init_hash(size_ht, ht);
printf("...\n");
return;
}
What you've made is an array of pointers to elements. However, the init_hash function seems to expect an array of elements. To create an array of elements the code should be as shown below. I've added some comments to highlight some of the changes.
typedef struct element{
char *key;
char *value;
}element;
typedef struct HashTable{
int size;
element *arr_table; // <-- only one '*', not two, to declare a pointer to an array of elements
}HashTable;
void init_hash(int size, HashTable *t)
{
if (size < 1)
return;
t->size = size;
t->arr_table = malloc(sizeof(element) * size); // <-- allocate memory for the elements, note 'sizeof(element)' not 'sizeof(element *)'
if (t->arr_table == NULL)
return;
int i;
for (i = 0; i < size; i++)
{
t->arr_table[i].key = NULL; // <-- table[i] is a structure, use dot notation
t->arr_table[i].value = NULL;
}
}
int main( void ) // <-- declare main with the correct signature
{
HashTable *ht = malloc(sizeof(HashTable)); // <-- don't cast the return value from malloc
int size_ht = 9;
init_hash(size_ht, ht);
printf("...\n");
}

C: Structs: How do I assign the size of an array when creating an instance of the struct?

Say I have this struct
typedef struct list
{
int index
node *arr[]
}
Is there any way to assign the size of the node array when creating the struct of type list?
If you are allocating objects dynamically, then you can use flexible arrays, which are part of C99 and later:
struct list
{
int index;
size_t num_elements;
node * arr[]; // note the empty "[]"
};
Usage:
struct list * p = malloc(sizeof(struct list) + n * sizeof(node *));
p->index = 101;
p->num_elements = n;
for (size_t i = 0; i != p->num_elements; ++i)
{
p->arr[i] = create_random_pointer();
}
// ...
free(p);

Hashing structures in C

So I'm attempting to implement a hash table that will hash structures containing words.
the structures will be similar to this:
#ifndef HASHTABLE_H
#def HASHTABLE_H
typedef int (*HashFunctionT) (char* string, int upperbound);
struct node_
{
char * word;
struct node * next;
}
typedef struct node_ * node;
struct nodehash_
{
int size;
struct node * hash[100];
}
typedef struct nodehash_ * nodehash;
Hashtable createHashTable();
void addtohash(node list, nodehash hash);
#endif
And I want the hash function to work something like this:
#include "hashtable.h"
int hashFunction(char *word, int hashTableSize)
{
int length = strlen(word);
int h = 0;
int i;
for(i = 0; i<length; i++)
{
h=31 *h + word[i];
}
return h % hashTableSize;
};
nodehash createHashtable()
{
nodehash hashtable;
hashtable = malloc(sizeof(struct nodehash_));
hashtable->size = 100;
hashtable->hash = malloc(100 * sizeof (node));
int i;
for (i = 0; i < hashtable->size; i++)
{
hashtable->table[i] = NULL;
}
return hashtable;
};
void addtohash(node list, nodehash hashtable)
{
int nodehashnumber;
nodehashnumber = hashfunction(list->word, hash->size);
hashtable->hash[nodehasnumber] = list;
};
And the main functio will look something like this (assume that the linked list of node structures has been created and filled).
int main()
{
nodehash hashtable = createhashtable();
node nodelist;
/* here the nodelist would be created and filled and such and such*/
while (nodelist->next != NULL)
{
addtohash(nodelist, hashtable);
}
return;
}
Assume that there can be no collisions, because every word to be hashed will be different.
BAsically, I'm wondering if I missed and glaring, obvious mistakes or flaws in logic.
Any help would be greatly appreciated.
Thanks.
I didn't give the code an extensive read, but the first thing that stood out pretty clearly is the hash table size, 100. It is best to use a prime number for the size of your hash tables to help avoid collisions.
You seem to have a problem with semicolons:
struct node_
{
char * word;
struct node * next;
} /* <<-- HERE */
typedef struct node_ * node;
But::
int hashFunction(char *word, int hashTableSize)
{
int length = strlen(word);
int h = 0;
int i;
for(i = 0; i<length; i++)
{
h=31 *h + word[i];
}
return h % hashTableSize;
}; /* <<-- NOT here */
Also, a wise advice is IMHO to use as many unsigned types as possible: for the hash value (what does modulo division do with a negative operand?) and for sizes and indexes.
Rule of thumb: if it can not be negative: it's unsigned.

Resources