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");
}
Related
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;
}
I've a problem with memory allocation for an hash table with linked list (for avoid collisions) in C.
I think that the problem is on allocation of an item.
I've made two scruct, one for the single item and one for the table.
The first have two pointer to next and prev item.
Please help me.
I stay on this code until 3 days.
The code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 50000
unsigned long hash(char *str) {
unsigned long int stringsum = 0;
for(; *str != '\0'; str++) {
stringsum += *str;
}
return stringsum % CAPACITY;
}
typedef struct item {
char *value;
char *key;
struct item *next;
struct item *prev;
} ht_item;
typedef struct hashtable {
ht_item **items;
int dim;
int count;
} HashTable;
HashTable* create_table(int size); HashTable* create_item(HashTable *table, char *value, char *key);
void print_table(HashTable* table, int dim);
int main(void) {
HashTable *table = create_table(CAPACITY);
table = create_item(table, "Giuseppe", "Nome");
print_table(table, CAPACITY);
return 0;
}
HashTable* create_item(HashTable *table, char *value, char *key) {
unsigned long index = hash(key);
printf("%u", index);
ht_item *_iterator; ht_item *prev;
for(_iterator = table->items[index], prev = NULL; _iterator != NULL; prev = _iterator, _iterator = _iterator->next);
_iterator = (ht_item*)malloc(sizeof(ht_item));
_iterator->key = (char*)malloc(200);
_iterator->value = (char*)malloc(200);
strcpy(_iterator->key, key);
strcpy(_iterator->value, value);
_iterator->next = NULL;
_iterator->prev = prev;
return table;
}
HashTable* create_table(int size)
{
HashTable *table = (HashTable*)malloc(sizeof(HashTable));
table->dim = size;
table->items = (ht_item**)calloc(size, sizeof(ht_item*));
for(int i = 0; i < size; i++){
table->items[i] = NULL;
}
return table;
}
void print_table(HashTable* table, int dim) {
for(int i = 0; i < CAPACITY; i++)
{
if(table->items[i] != NULL)
{ ht_item *_iterator = (ht_item*)malloc(sizeof(ht_item));
for(_iterator = table->items[i]; _iterator != NULL;
_iterator = _iterator->next)
{
printf("Key: %s\tValue: %s\n", _iterator->key, _iterator->value);
} free(_iterator);
}
}
}
Made some changes in your code. Please read through the blocks containing // CHANGE HERE comment.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 50000
// CHANGE HERE - additional parameter, value to be used for modulo
unsigned long hash(char *str, unsigned int mod_value) {
unsigned long int stringsum = 0;
for(; *str != '\0'; str++) {
stringsum += *str;
}
// CHANGE HERE - use mod_value instead of CAPACITY
return stringsum % mod_value;
}
typedef struct item {
char *value;
char *key;
struct item *next;
struct item *prev;
} ht_item;
typedef struct hashtable {
ht_item **items;
int dim;
int count;
} HashTable;
HashTable* create_table(int size); HashTable* create_item(HashTable *table, char *value, char *key);
void print_table(HashTable* table, int dim);
int main(void) {
HashTable *table = create_table(CAPACITY);
table = create_item(table, "Giuseppe", "Nome");
print_table(table);
return 0;
}
HashTable* create_item(HashTable *table, char *value, char *key) {
// CHANGE HERE - function arguments validation
if (table == NULL)
{
return table;
}
if (value == NULL || key == NULL)
{
printf("Key or value is null\n");
return table;
}
// CHANGE HERE - pass table->dim to hash
unsigned long index = hash(key, table->dim);
printf("Index: %lu\n", index);
// CHANGE HERE - simplified the code a bit
ht_item* new_node = malloc(sizeof(ht_item));
new_node->key = malloc(200 * sizeof(char));
strncpy(new_node->key, key, 200);
new_node->value = malloc(200 * sizeof(char));
strncpy(new_node->value, value, 200);
// CHANGE HERE - if first node in index
if (table->items[index] == NULL)
{
table->items[index] = new_node;
return table;
}
ht_item *cur, *prev = NULL;
for(cur = table->items[index]; cur != NULL; prev = cur, cur = cur->next);
prev->next = new_node; // CHANGE HERE - it seems this line was missing
new_node->prev = prev;
new_node->next = NULL;
return table;
}
HashTable* create_table(int size)
{
HashTable *table = (HashTable*)malloc(sizeof(HashTable));
table->dim = size;
table->items = (ht_item**)calloc(size, sizeof(ht_item*));
for(int i = 0; i < size; i++){
table->items[i] = NULL;
}
return table;
}
void print_table(HashTable* table) {
// CHANGE HERE - function arguments validation
if (table == NULL)
{
printf("Table is null\n");
return;
}
// CHANGE HERE - change CAPACITY to dim
for(int i = 0; i < table->dim; i++)
{
//printf("i = %d [%d]\n", i, table->items[i] == NULL);
if(table->items[i] != NULL)
{
// CHANGE HERE - removed unnecessary malloc
ht_item *_iterator = NULL;
for(_iterator = table->items[i]; _iterator != NULL; _iterator = _iterator->next)
{
printf("Key: %s\tValue: %s\n", _iterator->key, _iterator->value);
}
}
}
}
The create_item function can and should be simplified.
I have put some comments inline.
HashTable* create_item(HashTable *table, char *value, char *key) {
// use modulo operator here, not in the hash function
unsigned long index = hash(key) % table->dim;
// nicer way of allocating
ht_item *insert = malloc(sizeof *insert);
// use strdup to avoid wasted memory and buffer overflows
insert->key = strdup(key);
insert->value = strdup(value);
// head insert rather than tail
insert->next = table->items[index];
table->items[index] = insert;
return table;
}
I dropped the use of the prev member. If you need that somewhere it's an exercise for you to add it. I don't think it's necessary for a simple hash table.
I have made a Java like ArrayList class in C for educational purposes however currently it is only good for integers. I want to make it Generic so it can take any type of data. How do I go about it. I read somewhere about creating a typedef void pointer. Any thoughts ?
........................................................................................................
Here is My code
#ifndef ARRAYLIST_H
#define ARRAYLIST_H
typedef struct ArrayList ArrayList;
typedef int bool;
#define false 0
#define true 1
struct ArrayList {
int *con;
int numElements;
int conSize;
};
ArrayList *createArrayList();
void freeArrayList(ArrayList *);
void add(ArrayList *, int);
void printList(ArrayList *);
void resize(ArrayList *);
int remove(ArrayList *, int);
bool isEmpty(ArrayList*);
int getNumElements(ArrayList*);
int getConSize(ArrayList*);
#endif
_____________________________________
#include<stdio.h>
#include<stdlib.h>
#include"Consts.h"
#include "ArrayList.h"
#define CAPACITY 5
ArrayList *createArrayList() {
ArrayList *arrayList = malloc(sizeof(ArrayList));
arrayList->conSize = CAPACITY;
arrayList->numElements = 0;
arrayList->con = malloc(sizeof(int) * CAPACITY);
return arrayList;
}
void freeArrayList(ArrayList * arrayList) {
if (arrayList == NULL) {
return;
}else {
free(arrayList->con);
free(arrayList);
}
}
void add(ArrayList *arrayList, int input) {
//printf("Num elements in add method before adding %d \n", arrayList->numElements);
if (arrayList->numElements >= arrayList->conSize) {
resize(arrayList);
printf("resized\n");
}
int size = arrayList->numElements;
//add element to the last
arrayList->con[size] = input;
arrayList->numElements = arrayList->numElements + 1
}
void resize(ArrayList *arrayList) {
int num = arrayList->numElements;
int oldSize = arrayList->conSize;
int newSize = oldSize + 50;
int *temp = realloc(arrayList->con, sizeof(type) * newSize);
if (temp != NULL) {
arrayList->con = temp;
arrayList->conSize = newSize;
}
}
int remove(ArrayList * arrayList, int val) {
int i = 0;
while (arrayList->con[i] != val) {
i++;
}
//remove this index
if (i == arrayList->conSize) {
return -1;
}
else {
int removedVal = arrayList->con[i]; int j;
for (j = i; j < arrayList->numElements ; j++) {
arrayList->con[j] = arrayList->con[j + 1];
}
arrayList->con[j + 1] = NULL;
arrayList->numElements = arrayList->numElements - 1;
return removedVal;
}
}
If you want the array list be able to store any type of data, you need to
1) make con a void pointer. void *con;
2) store additional metadata in the struct about the memory alignment of the type
3) add one more parameter to the constructor of array list, which is the additional metadata mentioned in 2)
4) when allocating memory, use the stored metadata instead of sizeof(whatever), like temp=malloc(stored_metadata_about_type*50);
Also notice that it is not usually a good idea to hardcode 50, and better declare it as a constant like buffer_size.
I have a pointer to a pointer to a structure and I am trying to access a pointer-to-pointer pointer within that structure. I keep getting an error that reads: "request for member 'buckets' in something not a structure or union." I commented next to the error. So my question is, how do I properly access buckets and allocate memory for it.
typedef struct bucket {
char *key;
void *value;
struct bucket *next;
} Bucket;
typedef struct {
int key_count;
int table_size;
void (*free_value)(void *);
Bucket **buckets;
}
int create_table(Table ** table, int table_size, void (*free_value)(void *)){
int iterate = 0;
*table = malloc(sizeof(Table));
if(table && table_size != 0) {
(*table)->key_count = 0;
(*table)->table_size = table_size;
(*table)->free_value = free_value;
(*table)->buckets = malloc(table_size * sizeof(Bucket)); /* Error is here */
while(iterate < table_size)
*table->buckets[iterate++] = NULL;
return SUCC;
}
return FAIL;
}
By the look of your allocation:
(*table)->buckets = malloc(table_size * sizeof(Bucket));
It looks as though you are attempting to create space for table_size buckets and not table_size pointers to bucket. It the allocation should read:
(*table)->buckets = malloc(table_size * sizeof(Bucket*));
The error, I believe, is further down in the while loop. Operator -> has precedence over [] which has precedence over *, therefore you are actually saying *(table->buckets[iterate++]), and table is a pointer-pointer and does therefore not have a member called bucket.
(Note: You're missing a Table; in your second typedef.
int create_table(Table ** table, int table_size, void (*free_value)(void *)){
int iterate = 0;
*table = malloc(sizeof(Table));
if(table && table_size != 0) {
This isn't right. You should test table before you allocate memory, and then test *table.
(*table)->key_count = 0;
(*table)->table_size = table_size;
(*table)->free_value = free_value;
(*table)->buckets = malloc(table_size * sizeof(Bucket)); /* Error is here */
Here, you are allocating space for table_size number of Bucket, but assigning the memory to a pointer to pointer to Bucket. It looks like you want to allocate table_size number of pointers to Bucket.
while(iterate < table_size)
*table->buckets[iterate++] = NULL;
This is the same as *(table->buckets[iterate++]) which is obviously wrong. table is not a pointer to struct, *table is. This is where your real error is.
I would probably write something like this:
typedef struct {
int key_count;
int table_size;
void (*free_value)(void *);
Bucket **buckets;
} Table;
int create_table(Table **table, int table_size, void (*free_value)(void *))
{
if (!table || table_size == 0) {
return FAIL;
}
*table = malloc(sizeof(Table));
if (*table) {
(*table)->key_count = 0;
(*table)->table_size = table_size;
(*table)->free_value = free_value;
(*table)->buckets = malloc(table_size * sizeof(Bucket *));
if ((*table)->buckets) {
int iterate = 0;
while(iterate < table_size)
(*table)->buckets[iterate++] = NULL;
return SUCC;
}
}
if (*table) {
free ((*table)->buckets);
}
free (*table);
return FAIL;
}
Issues with reallocing the items list. I am trying to add items into the testList structs items, but i am getting memory address errors when trying to add or print the values for the individual ListItems. Any help would be greatly appreciated.
struct ListItems
{
int id;
int name;
};
struct testList
{
struct ListItems** items;
int count;
int size;
};
struct Test
{
struct testList* list;
};
void printArray(struct testList* list)
{
for (int i = 0; i < list->count; i++)
{
printf("id=%i, name= %i \n", list->items[i]->id, list->items[i]->name);
fflush(stdout);
}
printf("printing accomplished \n");
fflush(stdout);
}
void growArray(struct testList* list, struct ListItems* item)
{
int size = list->size;
list->items[list->count++] = item;
struct ListItems** user_array = list->items;
//printf("array count %i, array size %i \n", list->count, size);
if (list->size == list->count)
{
struct ListItems* temp = realloc(*user_array, (size * 2) * sizeof (struct ListItems));
if (temp == NULL)
{
printf("it's all falling apart! \n");
}
else
{
*user_array = temp;
list->size = size * 2;
}
}
}
/*
*
*/
int main(int argc, char** argv)
{
struct Test* test = (struct Test*) malloc(sizeof (struct Test));
test->list = (struct testList*) malloc(sizeof (struct testList));
test->list->count = 0;
test->list->size = 1;
test->list->items = (struct ListItems**) malloc(sizeof (struct ListItems*));
for (int i = 0; i < 32; i++)
{
struct ListItems* item = (struct ListItems*) malloc(sizeof (struct ListItems));
item->id = i;
item->name = i;
growArray(test->list, item);
}
printArray(test->list);
for (int j = 0; j < sizeof (test->list->items); j++)
{
free(test->list->items[j]);
}
free(test->list->items);
free(test->list);
free(test);
}
The problem starts with the declaration of struct testList. A pointer to an array of items should have just one *:
struct testList
{
struct ListItems* items; // Changed from pointer-to-pointer
int count;
int size;
};
This will force some other changes in the code.
Your growArray() needs to update list->items. In current code, it will point forever to an 1-element sized area only.
EDIT:
your realloc() allocates for sizeof (struct ListItems)) but pointer holds pointers, not elements.
I would write:
void growArray(struct testList* list, struct ListItems* item)
{
if (list->size <= list->count) {
size_t new_size = 2 * list->size;
struct ListItems** temp = realloc(list->items, new_size * sizeof temp[0]);
assert(temp);
list->size = new_size;
list->items = temp;
}
list->items[list->count] = item;
++list->count;
}
With this, you do not need the initial list->items = malloc(...) in main() but can assign NULL.
EDIT:
for (int j = 0; j < sizeof (test->list->items); j++)
does not make sense; you probably want to j < test->list->count.