I have the following Hash_table and Hash_bucket structs
typedef struct Hash_Table{
struct Bucket** bucket;
}Table;
typedef struct Bucket{
struct Bucket* next;
int num;
}Bucket;
I want to allocate 5 Hash Tables which i do like this,
Table** hash_tables = malloc(sizeof(Table*)* 5);
for(int i = 0; i <=4 ; i++){
hash_tables[i] = NULL;
}
To my knowledge, what I have done up to here is correct, and I want to proceed allocating the Hash Tables in my code. As i did with the double pointer above, my allocation for the Hash Table
hash_table[0] = malloc(sizeof(Table));
hash_table[0]->bucket = malloc(sizeof(Bucket*)*10); /* line 2 that is problematic*/
I allocate the size for a Hash_Table and then 10 Hash_Bucket pointers. However, I am having leaks and NOT because I free the memory wrongly. The line 2 of the allocation seems to be redundant (?) and if I replace the Hash_Table with
typedef struct Hash_Table{
struct Bucket* bucket[10];
}Table;
, then the line 2 is not needed, everything works perfect and memory is free'd. I really am clueless as to what I am doing wrong. I've found the mistake, but don't see the mistake in the first place. Thank you all.
The Code you posted without the "line 2 is redundant" part should look like this right:
typedef struct Bucket {
struct Bucket* next;
int num;
} Bucket;
typedef struct Hash_Table {
struct Bucket** bucket;
} Table;
int main(void)
{
// Create hashtable
Table** hash_tables = malloc(sizeof(Table*) * 5);
for (int i = 0; i <= 4; i++) {
hash_tables[i] = NULL;
}
// Create Bucket
hash_tables[0] = malloc(sizeof(Table));
hash_tables[0]->bucket = malloc(sizeof(Bucket*)*10); /* line 2 that is problematic*/
free(hash_tables[0]->bucket);
free(hash_tables[0]);
free(hash_tables);
return 0;
}
If you add the right free's at the bottom you shouldn't have memory leaks.
At least Valgrind says so.
Note: for every written malloc in your code, you need at least 1 free
Related
I'm trying to create a HashTable in C where each 'bucket' is a pointer to a LinkedList. That is, I need to create an array of LinkedList pointers.
As of now, SomeHashTable->Buckets[i] is returning a non-pointer LinkedList. I've been looking for answers everywhere and I just can't find anything. Perhaps I'm overlooking something? I've given my current code below.
HashTable.h
#include "LinkedList.h"
typedef struct HashTable
{
LinkedList* Buckets[1009];
} HashTable;
//Creates new hashtable
HashTable* HashTable_new();
//Hashes and adds a new entry
void HashTable_add(HashTable* Table, int data);
HashTable.c
#include "HashTable.h"
HashTable* HashTable_new()
{
HashTable* newTable = (HashTable*)malloc(sizeof(HashTable));
newTable->Buckets = malloc(1009 * sizeof(LinkedList*));
//Create linked lists
for (int i = 0; i < 1009; i++)
{
newTable->Buckets[i] = LinkedList_new();
}
return newTable;
}
void HashTable_add(HashTable* Table, int data)
{
int index = data % 1009;
//Get bucket to hash to
LinkedList* BucketHead = (Table->Buckets[index]);
//Hash it iiinnnn real good
LinkedList_add_at_end(BucketHead, data);
}
The linked List structs for reference:
typedef struct LinkedListNode {
int data;
struct LinkedListNode *next;
struct LinkedListNode *prev;
} LinkedListNode;
typedef struct LinkedList {
struct LinkedListNode *first;
struct LinkedListNode *last;
} LinkedList;
As H.S.'s comment mentions, there is no need to dynamically --and-- statically allocate the Buckets array.
This line:
newTable->Buckets = malloc(1009 * sizeof(LinkedList*));
is overwriting the pointer to the statically allocated array, which is probably not what you want. For scalability, I would ditch the static array and stick with malloc(). That way you could use an argument to HashTable_new() to specify the size of the buckets array, like so:
HashTable* HashTable_new(int nBuckets)
{
HashTable* newTable = (HashTable*)malloc(sizeof(HashTable));
newTable->Buckets = malloc(nBuckets * sizeof(LinkedList*));
newTable->nBuckets = nBuckets;
//Create linked lists
for (int i = 0; i < nBuckets; i++)
{
newTable->Buckets[i] = LinkedList_new();
}
return newTable;
}
Notice that newTable->Buckets is being allocated as a pointer to a pointer to LinkedList (LinkedList**). You'll need to keep track to the size of Buckets[], so add the variable to the struct as follows:
typedef struct HashTable
{
int nBuckets;
LinkedList **Buckets;
} HashTable;
You should be good as long as LinkedList_new()'s return type is LinkedList*, and don't forget to free() it all when you're done.
I have the following structures:
struct date {
int year;
int month;
int day;
};
struct person{
char name[64];
struct date birthday;
};
struct aop {
int max;
struct person **data;
};
I tried malloc for data within aop structure like this: (no errors occurred here)
struct aop *create_aop(int max) {
struct aop *s = malloc(sizeof(struct aop));
s->max = max;
s->data = malloc((sizeof(struct person)) * max);
return s;
}
But when I tried accessing "data" in other part of the code, such as this:
a->data[len]->birthday.year = birthday.year;
I got errors.
Am I doing malloc the wrong way, or am I accessing the data incorrectly?
Thank you in advance!
In aop structure you do not need double pointer for struct person. so
struct aop {
int max;
struct person **data;
};
change struct person **data;
to
struct person *data;
And while using that use it as below way.
a->data[len].birthday.year = birthday.year;
Field data in your aop structure is array of poiters, so at first you need to allocate memory for pointers:
s->data = malloc((sizeof(struct person*)) * max);
And then in loop you need to allocate memory for each structure:
for(i = 0; i < max; i++) {
s->data[i] = malloc(sizeof(struct person));
}
I've tried to create the same structure here, and I couldnt acess that structure Person.
Since you're willing to create multi person entries, how about creating a linked list?
Like:
struct aop {
int max;
struct person **data;
};
struct person{
char name[64];
struct date birthday;
struct person *nextPerson;
};
Probably it will work.
Am I doing malloc the wrong way, or am I accessing the data incorrectly?
Yes. Study this incredibly informative diagram:
Type *****var = malloc (sizeof(Type****) * n_items);
/* ----- ---- */
/* | | */
/* +---> n stars +---> n-1 stars */
If you have more than one star, you are not done yet. You need to allocate the data at the next level of indirection:
for (i = 0; i < n_items; ++i)
{
var[i] = malloc (sizeof(Type***) * n_items_level2);
/* --- */
/* | */
/* +---> n-2 stars */
If you still have stars, you are not done yet. You need to allocate the data at the next level of indirection in a nested loop:
for (j = 0; j < n_items_level2; ++j)
{
var[i][j] = malloc (sizeof(Type**) * n_items_level3);
and so on until you run out of stars.
I am unsure what it is I am doing wrong when initialising this hash table. Can anyone help? I am getting a segfault at the initialisation of the bucket list in the for loop, where I have labelled it.
#define BUCKETMAX 20
#define TABLESIZE 100
//Node to hold entry
typedef struct node{
MEntry *entry;
struct node *next;
}MListNode;
//Bucket linked list to hold Nodes
typedef struct bucket{
int size;
MListNode *top;
}BucketList;
//Hash table to hold Bucket Lists
typedef struct mlist{
int capacity;
BucketList **bList;
}MList;
MList *ml_create(void){
//Initialising the hash table
MList *ml;
//Check if memory if available to be allocated before assigning capacity
if((ml = (MList *) malloc(sizeof(BucketList **) * TABLESIZE)) == NULL){
fprintf(stderr, "Hash Table Could Not be Created (Not Enough Memory)\n");
exit(EXIT_FAILURE);
}else{
ml->capacity = TABLESIZE;
//Initialise the bucket lists
int i;
for(i =0; i<TABLESIZE;i++){
/****************************************************************
SEGFAULT IS HERE */
if((ml->bList[i] = (BucketList *) malloc(sizeof(MListNode *) * BUCKETMAX)) == NULL){
/****************************************************************/
fprintf(stderr, "Bucket List Could Not be Created (Not Enough Memory)\n");
exit(EXIT_FAILURE);
}else{
ml->bList[i]->size = 0;
ml->bList[i]->top = (MListNode *) NULL;
}
}
}
return ml;
}
Any help would be appreciated, thanks.
You cannot allocate memory for structures the way you do.
ml = (MList *) malloc(sizeof(BucketList **) * TABLESIZE)
That line allocates memory to the MList structure ml, but not to its member ml->bListwhich you are then filling in the loop at the point of the segfault.
You need to allocate memory for both purposes separately:
ml = malloc(sizeof(MList));
ml->bList = malloc(sizeof(BucketList*) * TABLESIZE);
The same applies to the latter memory allocation for ml->bList[i].
So I have a linked list set up like this:
#define MAX 20
//structure for a single linked list
typedef struct element {
int info;
struct element *link;
} Tnode;
//structure for a grapgh
typedef struct graphAdjList {
int nodes;
Tnode *adjList[MAX];
} Tgraph;
In my code I have it set up like this:
Tgraph *graph;
graph = (Tgraph*) malloc(sizeof(Tgraph));
graph -> nodes = 0;
for(i; i < 20; i++){
graph->adjList[i]= NULL;
}
graph->adjList[2]->info = 222;
Now if I compile this I get an access violation on this last line. Is it that I have not reserved memory for the Tnode part of the struct or am I missing something. How can I initialize the array so that I can assign a value to info in any element of the array?
Thank you
Jason
You are right, the issue is that you have not allocated memory for the individual nodes in adjList.
When you do graph->adjList[2]->info = 222;, graph->adjList[2] is still NULL from the for loop right before it.
To fix this, you need to first allocate memory for it like so:
graph->adjList[2] = malloc(sizeof(TNode));
Note: You could just replace graph->adjList[i] = NULL; with graph->adjList[i] = malloc(sizeof(Tnode)); in the for loop, but allocating as you go can be useful for memory efficiency.
You need to replace
graph->adjList[i]= NULL;
to
graph->adjList[i] = (Tnode*)malloc(sizeof(Tnode));
I am creating a simple graph with nodes and edges. I got the functionality going but got some memory bugs.
I have a typedef struct in header file:
typedef struct Graph_s* Graph;
And implementation in c. file:
struct Graph_s {
Node* nodeArray;
Edge* edgeArray;
size_t edges;
size_t nodes;
};
And function for construction:
Graph create_graph() {
Graph newGraph = malloc(sizeof(Graph));
newGraph->edges = 0;
newGraph->nodes = 0;
return newGraph;
}
The line Graph newGraph = malloc(sizeof(Graph)) gives: Invalid write of size 8 from Valgrind.
malloc(sizeof(Graph)) is only allocating enough memory for a pointer. Change it to malloc(sizeof(struct Graph_s)).