I'm learning hashtable data structures and I want to make a hashtable with a flexible length array of pointers to struct Link (linked list pieces), so that hashtable initialization will set the array to be a length input into the initialization function.
At first I was getting the error "flexible array not at the end of struct". When its at the end (as shown) the program crashes (but it still compiles). This is my code:
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
int numberOfEntries;
int numberOfBuckets;
Link *Table[];
} HashTable;
HashTable *hashtableInit(int size){
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
It works if I set the array to a constant and input the same value into the init function:
#define SIZE 11
typedef struct Link{
int key;
char *name;
struct Link *next;
} Link;
typedef struct HashTable{
Link *Table[SIZE];
int numberOfEntries;
int numberOfBuckets;
} HashTable;
HashTable *hashtableInit(int size){ // works if SIZE is passed into function as size parameter
HashTable *newHT = malloc(sizeof(HashTable));
if (newHT != NULL){
newHT->numberOfEntries = 0;
newHT->numberOfBuckets = size;
for (int i = 0; i < newHT->numberOfBuckets; i += 1){
newHT->Table[i] = NULL;
}
return newHT;
} else {
printf("Error in memory allocation.\n");
fflush(stdout);
return NULL;
}
}
}
The second code block works perfectly. Any insights would be greatly appreciated. Thanks for your time.
Chris
You should allocate memory as
HashTable *newHT = malloc(sizeof *newHT + size * sizeof newHT->Table[0]);
Your
HashTable *newHT = malloc(sizeof(HashTable));
is wrong, because no space is given for the flexible array member. Should probably be
HashTable *newHT = malloc(sizeof(HashTable)+size*sizeof(Link*));
Related
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)
I have a program in C that creates a hash table.
memset is Okay but, i want to initialize with for loop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HSZ 127
#define HASHING(x) ((x)%HSZ)
struct node_t{
int val;
struct node_t *next;
};
struct node_t *hash_table[HSZ];
void init(void){
int i;
//memset(hash_table,0,sizeof(hash_table));
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
}
void insert_hash(int value){
int key = HASHING(value);
struct node_t *newNode = (struct node_t*)malloc(sizeof(struct node_t));
newNode->val = value;
newNode->next = NULL;
if(hash_table[key] == NULL){
hash_table[key] = newNode;
} else {
newNode->next = hash_table[key];
hash_table[key] = newNode;
}
}
int delete_hash(int value){
int key = HASHING(value);
if (hash_table[key] == NULL)
return 0;
struct node_t *delNode = NULL;
if (hash_table[key]->val == value){
delNode = hash_table[key];
hash_table[key] = hash_table[key]->next;
} else {
struct node_t *node = &hash_table[key];
struct node_t *next = hash_table[key]->next;
while (next){
if (next->val == value){
node->next = next->next;
delNode = next;
break;
}
node = next;
next = node->next;
}
}
return 1;
free(delNode);
}
void PrintAllHashData()
{
printf("###Print All Hash Data###\n");
for (int i = 0; i < HSZ; i++){
if (hash_table[i] != NULL){
printf("idx : %d ", i);
struct node_t *node = hash_table[i];
while (node->next){
printf("%d ", node->val);
node = node->next;
}
printf("%d\n", node->val);
}
}
}
int main(void){
init();
insert_hash(1);
insert_hash(3);
insert_hash(128);
PrintAllHashData();
}
look at this code.
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
The IDE I am using does not throw up a compilation error when I compile the code, but during the execution the code faults and is terminated/haulted. I tried debugging the code, it faults at this line and is stopped, I think BAD ACCESS points to Segmentation Error.
then, I changed this line to
for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}
but, then I got the compilation error stating 'structure type require instead of 'struct node_t *'
I think that I don't understand clearly about struct in C.
How to fix this problem?
What you are dealing with is Undefined Behavior.
See, struct node_t *hash_table[HSZ];
So, hash_table is an array of HSZ (127) pointers of the data type struct node_t.
When you do,
for(i=0; i<HSZ; i++){
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
hash_table[0] to hash_table[126] pointers are not pointing to anything.
So, each of them (or all of them) should be initialized first to point to an object of the type struct node_t and then you can initialize them. For that matter, Using a memset does not cause a problem because memset is filling the contents of the pointers with all zeros. There is difference between filling the pointers with all zeros and filling all zeros to the memory pointed by pointers.
Trying this,
for(i=0; i<HSZ; i++){
hash_table[i].val = 0;
hash_table[i]->next = NULL;
}
is plain wrong.
To fix the issue you are facing, you need to allocate memory dynamically using malloc. You can do the in your for loop.
for(i = 0; i < HSZ; i++)
{
//Allocate memory of the size struct_node_t
hash_table[i] = malloc(sizeof(struct node_t)); //Do not cast!
//Check if memory is allocated
if(hash_table[i] == NULL)
{
//Memory not allocated, set some error state to handle and break
break;
}
//Initialize to zero
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
struct node_t{
int val;
struct node_t *next;
};
struct node_t *hash_table[HSZ];
when you have *hash_table[HSZ], this varible hash_table is a pointer. so whatever your action is , use hash_table-> ,syntax for pointer, mean point to somewhere.
a suggestion that when you use pointer you should always allocate memory hash_table[i] = malloc(sizeof(struct node_t));
struct node_t hash_table;
but if you initilize your varible like this, you can use hash_table.val = 0
so the way of assign value depend on how you declare your varibles
struct node_t *hash_table[HSZ];
gives you an array of pointers that are unset (i.e. not pointing to anything)
void init(void) {
int i;
// memset(hash_table,0,sizeof(hash_table));
for (i = 0; i < HSZ; i++) {
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
tries writing to your invalid pointers which gives undefined behavior.
Either make the array an array of structs (instead of pointers):
struct node_t hash_table[HSZ];
...
/* note use of . instead of -> since we have structs not pointers */
hash_table[i].val = 0;
or allocate the necessary structs so the array points to something:
for (i = 0; i < HSZ; i++) {
hash_table[i] = malloc(sizeof(struct node_t));
hash_table[i]->val = 0;
hash_table[i]->next = NULL;
}
typedef struct {
List *table;
unsigned int size;
} HashTable;
typedef struct node {
Data data;
struct node *next;
} NODE;
struct listptrs {
NODE *tail;
NODE *head;
NODE *prev;
NODE *current;
};
typedef struct listptrs List;
HashTable createHashTable(unsigned int size) {
//HashTable htable = { 0 };
//return htable;
int i;
HashTable *htable = NULL;
htable = malloc(sizeof(HashTable) * size);
for (i = 0; i < size; i++) {
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return *htable;//???
}
Then in main:
HashTable htable = createHashTable(tableSize);
htable doesn't act like an array at all. Any ideas how to solve it without changing any return value from the function and arguments for functions? This is part of a school assignment and only the contents of the function createHashTable may be changed. The rest of the program is not here because it isn't relevant to the question.
You maybe want this:
HashTable *createHashTable(unsigned int size)
{
//HashTable htable = { 0 };
//return htable;
int i;
HashTable* htable = NULL;
htable = malloc(sizeof(HashTable)* size);
for(i=0; i<size; i++)
{
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return htable;
}
As you allocate the array dynamically, you can simply return the newly allocated pointer. Returning a HashTable as you were trying doesn't make senses, because this would allow you to return one single HashTable, but you want to return a whole array of HashTables.
Usage:
Instead of:
HashTable htable = createHashTable(tableSize);
You need this:
HashTable *htable = createHashTable(100);
...
... // when done you need to delete the hashtable
deleteHashTable(htable);
The deleteHashTable is yet to be written, It essentially needs to free the table pointer and to free the table itself.
Now if you really are allowed to change only the contents of the createHashTable function but not the function signature, then your question doesn't make sense because with the function signature HashTable createHashTable(unsigned int size) you can only return one HashTable but not an array of HashTables.
But then maybe you actually want this:
HashTable createHashTable(unsigned int size)
{
HashTable htable = { 0 };
int i;
for(i=0; i<size; i++)
{
htable[i].table = malloc(sizeof(List));
htable[i].table->current = NULL;
htable[i].table->head = NULL;
htable[i].table->prev = NULL;
htable[i].table->tail = NULL;
htable[i].size = size;
}
return htable;
}
With this second solution, you still need to write the function that deletes the hash table.
The hash table itself isn't supposed to "behave like an array", and this:
return *htable;
makes no sense, it returns the first element from your array of hash tables.
You're not supposed to create an array of hash tables though, you're supposed to create a single hash table, which might contain an array (that's the table). It also has a size variable for instance, so there's more than the array itself to the hash table.
You should do
htable = malloc(sizeof *htable);
to allocate a single instance, then initialize that as needed and return it.
There seems to be some confusion here: createHashTable() is not supposed to allocate an array of hash tables, but a HashTable structure with an initial size for its embedded table member.
Furthermore, it is non standard practice to return the structure by value. You should instead return the pointer to the allocated HashTable or possibly take a pointer to HashTable structure allocated dynamically or statically by the caller and initialize that.
Here is a modified version of the code for this approach:
#include <stdlib.h>
typedef struct {
List *table;
unsigned int size;
} HashTable;
typedef struct node {
Data data;
struct node *next;
} NODE;
struct listptrs {
NODE *tail;
NODE *head;
NODE *prev;
NODE *current;
};
typedef struct listptrs List;
HashTable *createHashTable(unsigned int size) {
HashTable *htable = malloc(sizeof(*htable));
if (htable == NULL)
return NULL;
}
htable->size = size;
htable->table = NULL;
if (size == 0) {
return htable;
}
htable->table = malloc(sizeof(*htable->table) * size);
if (htable->table == NULL) {
free(htable);
return NULL;
}
for (unsigned int i = 0; i < size; i++) {
htable->table[i].head = NULL;
htable->table[i].tail = NULL;
htable->table[i].prev = NULL;
htable->table[i].current = NULL;
}
return htable;
}
Calling from main():
HashTable *htable = createHashTable(100);
I currently having a problem assigning a NODE type object to a NODE* array that is inside of an INV_PAGE_TABLE structure.
The structures look as follows:
typedef struct node {
int pid;
int p;
int offset;
unsigned TAG;
} NODE;
typedef struct invTablePage {
NODE *pageTable;
int frameSize;
int currentSize;
int totalSize;
int oldest;
int maxIndex;
} INV_PAGE_TABLE;
The invTablePage is allocated as follows:
void initInverted(INV_PAGE_TABLE *invTable, int memSize, int frameSize) {
//Malloc inverted page table
invTable = malloc(sizeof(struct invTablePage));
//Save frameSize
invTable->frameSize = frameSize;
//Save totalSize
invTable->totalSize = memSize / frameSize - 1;
//Save currentSize
invTable->currentSize = 0;
//Set oldest
invTable->oldest = 0;
//Malloc array inside of page table
invTable->pageTable = malloc(sizeof(NODE) * invTable->totalSize);
}
And finally the method which invokes a Segmentation Fault
void addToPageTable(struct invTablePage *invTable, NODE *node) {
NODE tempNode;
//If pageTable is not full
int currentSize = invTable->currentSize;
if (invTable->currentSize != invTable->totalSize) {
//Add Entry at index of currentSize
/*FOLLOWING LINE CRASHES PROGRAM*/
invTable->pageTable[currentSize] = node;
//Update currentSize
invTable->currentSize++;
//If pageTable is full
} else {
//Set temp to oldest
tempNode = invTable->pageTable[invTable->oldest];
//Set oldest to node
invTable->pageTable[invTable->oldest] = *node;
}
}
Notice that, in an array [10] for example, index runs from 0 to 9
So your total size should be invTable->totalSize = memSize/frameSize;
And currentSize shouldn't exceed invTable->totalSize - 1.
But I think you have to allocate memSize/frameSize and not memSize/frameSize - 1...
I'm not sure my answer is right, try some printf...
I have 2 structures in my C code. I want to write a hash function with these 2 structures. So I want to initialize my data null in first case. My code is
struct HashNode
{
char username[20];
char password[20];
};
struct HashTable
{
int size;
struct HashNode *table;
};
HashTable *initializeTable(int size)
{
HashTable *htable;
if (size < MIN_TABLE_SIZE)
{
printf("Table Size Small\n");
return NULL;
}
htable = (HashTable *)malloc(sizeof(Hashtable));
if (htable == NULL)
{
printf("memory allocation pblm\n");
return NULL;
}
htable->size = size;
}
How can I allocate memory for htable->table with that size? I have code in C++ like htable->table = new HashNode [htable->size];. How can I write this in C using malloc?
You can allocate the memory in this way
htable->table = malloc(size*sizeof(HashNode))