Updated question is here
Memory allocation problem in HashTable
I'm working on making a HashTable in C. This is what I've done. I think I'm going on a right path but when I'm trying to
main.c
HashTablePtr hash;
hash = createHashTable(10);
insert(hash, "hello");
insert(hash, "world");
HashTable.c
HashTablePtr createHashTable(unsigned int capacity){
HashTablePtr hash;
hash = (HashTablePtr) malloc(sizeof(HashTablePtr));
hash->size = 0;
hash->capacity = capacity;
ListPtr mylist = (ListPtr)calloc(capacity, sizeof(ListPtr)); /* WHY IT DOESN'T ALLOCATE MEMORY FOR mylist HERE?? */
mylist->head = NULL;
mylist->size = 0;
mylist->tail = NULL;
hash->list = mylist;
return hash;
ListPtr is a LinkedList ptr
List.h
typedef struct list List;
typedef struct list * ListPtr;
struct list {
int size;
NodePtr head;
NodePtr tail;
};
...
...
HashTable.h
typedef struct hashtable * HashTablePtr;
typedef struct hashtable HashTable;
struct hashtable {
unsigned int capacity;
unsigned int size;
ListPtr *list;
unsigned int (*makeHash)(unsigned int, void *);
};
...
...
When I run my debugger, I see no memory being allocated to myList. In above example, my attempt is to make it an array of 10 lists.
Please help me to solve this.
I'm not that expert in C, if that helps.
calloc(capacity, sizeof(ListPtr)
should be
calloc(capacity, sizeof(List)
I think there are a whole host of problems here. You haven't included the error you getting so, I will list a couple:
hash = (HashTablePtr) malloc(sizeof(HashTablePtr*)); - You are allocating the size of a HashTable **, which is four bytes, you need to allocate the size of the underlying object.
ListPtr mylist = (ListPtr* )calloc(capacity, sizeof(ListPtr)); - Again, your are allocating the size of the pointer rather than the underlying list object.
HashTablePtr createHashTable(unsigned int capacity)){ - You are probably getting a compile error here with the extra parens and the inconsistent number of parameters.
Personally I am not a huge fan of using typedefs, especially when you are a beginner. I think that may be partially what is confusing you. You are better avoiding things like:
typedef struct hashtable * HashTablePtr;
Using to many typedefs will make your code harder to read since you will need to constantly look up what they are referring too.
The main problem is that you were allocating the memory for the size of a hashtable/list pointer and not for the size of their respected structures. I think the code below shows this well. You will also want to check if you allocations worked. If malloc, calloc, realloc. etc. fail they return NULL. If this happens and you do not check for this case you will get a segfault error and your program will crash.
Also follow the c99 standard, and put all of your variable declarations at the start of the function.
c99 std
malloc manpage
struct hashtable *
createHashTable(unsigned int capacity){
struct hashtable *hash;
struct list *mylist;
/* You want to allocate size of the hash structure not the size of a pointer. */
hash = malloc(sizeof(struct hashtable));
// always make sure if the allocation worked.
if(hash == NULL){
fprintf(stderr, "Could not allocate hashtable\n");
return NULL;
}
hash->size = 0;
hash->capacity = capacity;
/* Unless you need the memory to be zero'd I would just use malloc here
* mylist = calloc(capacity, sizeof(struct list)); */
mylist = malloc(capacity * sizeof(struct list));
if(mylist == NULL){
fprintf(stderr, "Could not allocate list\n");
free(hash); /* free our memory and handle the error*/
return NULL;
}
mylist->head = NULL;
mylist->size = 0;
mylist->tail = NULL;
hash->list = mylist;
return hash;
}
Also remember to free you list before you free your hashtable:
free(myhash->list);
free(myhash);
You are allocating a contigous block of ListPtr's, but you actually want to allocate space for the all the structures rather than just pointers (ListPtr) to those structures:
calloc(capacity, sizeof(List));
I agree with gman's comment about not hiding pointers. When coding in C, I never typdef a List * as a ListPtr. It makes the code harder to understand.
Related
I am studying C (self-study, not in an educational institution) and have been trying to build a hashtable data structure as part of my learning.
Please refer to this hopefully reproducible example:
#include <stdio.h>
#include <stdlib.h>
struct table_item {
char *name;
char gender;
char *birthdate;
char *address;
};
struct list_node {
struct table_item *data;
struct list_node *next;
unsigned long long hash_key;
};
struct hashtable {
int table_size;
int num_entries;
struct list_node **entries;
};
struct hashtable* init_hashtable(int size);
void free_hashtable(struct hashtable *table);
int main(void)
{
struct hashtable *hashtable = NULL;
int size_entry = 0;
printf("Input hashtable array size: ");
while (size_entry < 1) {
scanf(" %d", &size_entry);
}
hashtable = init_hashtable(size_entry);
free_hashtable(hashtable);
return 0;
}
struct hashtable* init_hashtable(int size) {
struct hashtable* new_table;
if ((new_table = malloc(sizeof(struct hashtable))) == NULL) {
perror("Error: failed to allocate memory for hash table\n");
exit(EXIT_FAILURE);
}
new_table->table_size = size;
new_table->num_entries = 0;
if ((new_table->entries = malloc(size*sizeof(struct list_node))) == NULL) {
perror("Error: failed to allocate memory for hash table array\n");
exit(EXIT_FAILURE);
}
return new_table;
}
void free_hashtable(struct hashtable *table) {
for (int i = 0; i < table->table_size; i++) {
if (table->entries[i] != NULL) {
free_list(table->entries[i]);
table->entries[i] = NULL;
}
}
free(table->entries);
free(table);
}
My issue is that trying to free the table always fails, even if I have not added anything to it.
I used GDB to check the issue. It seems that, in the above for loop, if (table->entries[i] != NULL) always fires (such as when i=0) even when I haven't added anything. This results in my free_list function trying to free inappropriate memory, which is why I get the stack dump.
Somehow it seems that table->entries[i] is actually not NULL but rather has a struct list_node * type, causing the if condition to fire inappropriately. Could somebody please explain to me why this is?
I was hoping that I could use this for loop to go through the entries array and only free memory where malloced nodes exist, but as it stands this will just crash my program. I am not sure how I can alter this to behave as I'd like it to.
Somehow it seems that table->entries[i] is actually not NULL
Indeed, because you never initialized it to NULL.
init_hashtable allocates space using malloc and points table->entries. Now malloc does not initialize the memory it provides. Its contents are garbage, and in particular, there is no reason why it should consist entirely of NULL pointers as your code expects.
If you want table->entries to be full of NULL pointers then you have to explicitly initialize it, either with a loop, or with memset(entries, 0, size*sizeof(struct list_node *)). Or best of all, by calling calloc instead of malloc, which also avoids bugs in case the multiplication size*sizeof(struct list_node *) overflows.
(Technically memset and calloc initialize memory to all-bits-zero, which in theory does not have to correspond to NULL pointers, but it actually does on all systems you are likely to encounter. But to be pedantic, the loop is the only strictly conforming way to do it.)
but rather has a struct list_node * type,
This has nothing to do with types. Types in C are statically determined from declarations, and there is no way for an object to have an unexpected type at runtime. The type of table->entries[i] is struct list_node * no matter what. The question is about the value of that object; you expect it to be NULL but it's not. "Null pointers" are not a separate type in C; NULL is simply a value that a pointer of any type may have.
As Avi Berger points out, there is another bug in that the size calculation in the malloc should be size*sizeof(struct list_node *) not sizeof(struct list_node). Each element is not a struct list_node but rather a pointer. In this case a struct list_node is larger than a pointer, so it's just wasting memory and not causing any other harm, but it should be fixed.
Somehow it seems that table->entries[i] is actually not NULL but rather has a struct list_node * type, causing the if condition to fire inappropriately. Could somebody please explain to me why this is?
You dynamically allocate space for table->entries. The initial contents of that allocated space are unspecified, so until you assign values to its contents, it is unsafe to have any particular expectations about them. In particular, you cannot assume that any or all elements will contain null pointers.
If you want to rely on those values to tell you something about what kind of cleanup needs to be performed, then you should set them all to appropriate values, I guess NULL, immediately after allocating the space.
Note also that there are null pointer values of every pointer type, so being null and having type struct list_node * are not mutually exclusive.
I am trying to understand malloc() better when it comes to linked list. Does this create memory for the pointer to the list as well as the fields inside of it?
Such as:
SomeStruct * someStructPtr = (SomeStruct *) malloc(sizeof(SomeStruct));
Alongside this, if I am trying to free this node AND the fields inside of it. Do I need to walk through all the fields (see code below). Does this just free the pointer (created from the line above) or does it free the pointer and and the fields.
free(someStructPtr);
For a more direct example. I have a struct of List and I'm trying to allocate space for this struct AND it's fields when it is created. I want to make sure I am creating, deleting, and using stdrup() correctly. My code is below:
Struct Declaration:
typedef struct ListNode_st
{
char * str;
struct ListNode_st * next;
} List;
Create Node:
List * List_createNode(const char * str){
List * listPointer = (List *) malloc(sizeof(List));
//make sure there was enough memory
if(listPointer == NULL)
return NULL;
//malloc for next
listPointer.next = (List *) malloc(sizeof(List *));
if(listPointer.next == NULL)
return NULL;
listPointer.next = NULL;
//malloc for str
listPointer.str = strdup(str);
//make sure enough space for the string to be copied
if(listPointer.str == NULL)
return NULL;
//return value
return listPointer;
}
Delete Node:
void List_destory(List * list){
//base case -- (last item)
if(list == NULL)
return;
//recurse case -- (there are more items)
List_destroy(list->next);
if(list->str != NULL)
free(list->str);
if(list->next != NULL)
free(list->next);
free(list);
}
Please don't cast the return value from malloc().
malloc(sizeof(SomeStruct))
allocates enough memory for one struct, and you then have to initialise every field within the struct.
calloc(1, sizeof(SomeStruct))
does the same but every byte of the struct is initialised to 0. malloc() and calloc() know nothing about your struct, they simply allocate the amount of memory you asked for. They return a void* pointer so that they can be used with any data type, about which they neither know nor care.
When you come to free() the allocated memory, the same applies - free() knows nothing about your struct, or even if it is a struct. It's up to you to free() any memory allocation within that struct, before you free() the memory for the struct. It does not free a struct. It frees the memory where the struct is.
So the answer is yes, you do need to walk through the whole data structure, otherwise any nested memory allocation pointers will be lost, resulting in memory leak.
List * List_createNode(const char * str){
List * listPointer = (List *) malloc(sizeof(List));
if(listPointer == NULL)
return NULL;
listPointer->next = NULL;
listPointer->str = strdup(str);
if(listPointer->str == NULL){
free(listPointer);
return NULL;
}
return listPointer;
}
void List_destory(List * list){
if(list == NULL)
return;
List_destroy(list->next);
free(list->str);
free(list);
}
Let's warm up a little before we tackle your question.
int x = 42;
Where does the memory of x come from? Is it allocated? Where? If this line is inside a function, the answer is: it is an "automatic" variable and the memory it uses is on the stack.
int * y = NULL;
Where does the memory for y come from now? There was no call to malloc() here and yet, y exists.
By now, you should be able to answer the first part of your question. malloc() is not allocating the memory for your pointer in this case.
struct Node
{
struct Node * next;
int value;
};
void InitNode( Node *node, int value )
{
if(NULL != node)
{
node->next = NULL;
node->value = value;
}
}
// Not on HEAP, not on stack! Where?
// This one gets its memory from "initvars" section.
int foo = 69;
int main( int argc, const char * argv[] )
{
struct Node n1; // instance located on stack...
InitNode(&n1); // no malloc() to be seen...
// Instance located on HEAP, but n2, the pointer is located on stack,
// just like an int x = 42 would be.
struct Node *n2 = malloc(sizeof(struct Node));
}
So, obviously in order to de-mystify what malloc() does requires to understand the different types of memory and how to deal with it.
So far we saw "automatic" aka "stack memory", we saw "initvars" memory. And we saw "heap" memory. malloc() is the function you use to allocate memory on the heap.
Last not least, there are yet other types of memory I will not mention here.
Does this create memory for the pointer to the list as well as the fields inside of it?
Given your struct type
typedef struct ListNode_st
{
char * str;
struct ListNode_st * next;
} List;
the following call will create memory for an instance of that struct:
List *l = malloc( sizeof *l ); // note no cast, operand of sizeof
l points to a block of memory large enough to contain two pointers; however, nothing's been allocated for either str or next to point to. You would have to allocate memory for the string and the next node separately:
l->str = malloc( N * sizeof *l->str ); // allocate N characters
or
l->str = strdup( str );
Note that in most linked list implementations, you don't allocate memory for next when you create a new node; that field is meant to point to another, previously allocated node in the list. You will set it when you insert a node following the current node.
Alongside this, if I am trying to free this node AND the fields inside of it. Do I need to walk through all the fields (see code below). Does this just free the pointer (created from the line above) or does it free the pointer and and the fields.
You need to free any allocated members first before deleting the entire node, such as
free( l->str );
free( l );
Freeing l does not free the memory that l->str points to.
This is my data structure for an Assignment I'm doing in class. I'm supposed to implement a a hash set that holds a string of linked lists. Each of those individual linked lists holds an int. My list is generic, if it works, using (void* data) like this:
typedef struct NodeStruct {
void *data;
struct NodeStruct* next;
struct NodeStruct* prev;
} NodeStruct;
// Rename NodeStruct* as NodePtr
typedef NodeStruct* NodePtr;
typedef struct ListStruct {
int elementType;
NodePtr first;
NodePtr last;
NodePtr current;
} ListStruct;
// ListHndl is just a ListStruct* renamed.
First question: Right now, I"m using memcpy(list->data, data, list->elementType).
I was wondering.. is it okay do just store it directly, like list->data = data?
This is my hash set struct:
typedef struct HashStruct {
int size;
int load;
ListHndl *chain; //An array of Linked Lists.
} HashStruct;
typedef HashStruct* HashHandle
HashHandle new_hashset(int size) {
HashHandle tempHash = malloc (sizeof (HashStruct));
assert (tempHash != NULL);
tempHash->size = size;
tempHash->load = 0;
tempHash->chain = malloc (sizeof (ListHndl) * size);
assert(tempHash->chain != NULL);
for (int i = 0; i < size; i++) {
tempHash->chain[i] = newList(sizeof(char*));
tempHash->chain[i]->data = malloc(sizeof (ListHndl)); // Error here
}
return tempHash;
}
This is the error that I'm getting.
hash.c: In function ‘new_hashset’:
hash.c:28:27: error: dereferencing pointer to incomplete type
tempHash->chain[i]->data = malloc(sizeof (ListHndl));
^
Second question: I'm not sure how I'm supposed to be allocating memory for these linked lists, which is probably why I got this error.
Am I even implementing this data structure correctly? If more information is needed, please let me know. Thank you!
First question: Right now, I"m using memcpy(list->data, data, list->elementType). I was wondering.. is it okay do just store it directly, like list->data = data?
That depends on what 'data' is pointing to. It is quite common to list->data = data when 'data' is pointing to memory allocated from the heap,
Second question: I'm not sure how I'm supposed to be allocating memory for these linked lists, which is probably why I got this error.
For the typedefs outlined in the question, you will need to allocate memory for:
Each new node: newNode=malloc(sizeof(NodeStruct))
Each node payload: newNode->data = malloc(sizeof(int))
Am I even implementing this data structure correctly?
It is difficult to say with the limited code provided. Of course, there are many ways to accomplish the assigned task; including those ways that are easier to understand, as well as those which are specifically tuned for performance.
I have a struct called course and each course has multiple nodes (another struct 'node').
The number of nodes it has varies but I am given that number from a file that I am reading this information from, so that number sits in a variable.
So I need a malloc inside the struct. But I am confused. I know you can have arrays in structs but I don't know where to put the code that creates the malloc array since my struct is in my header file. Here's my code at the moment. I realize it looks wrong, I just don't know how I can fix it and where to initialize the malloc array.
struct course {
char identifier[2];
int num_nodes;
struct node *nodes;
nodes = (struct nodes*)malloc(num_nodes*sizeof(struct node));
};
struct node {
int number;
char type[2];
};
I want to be able to do something like:
struct node a_node;
struct course a_course;
a_course.nodes[0] = a_node;
etc...
I haven't used much C, this is the first time I've ever tried using dynamic arrays in C. My experience all comes from Java, and of course Java doesn't really use pointers in the same way as C so it's all a tad confusing for me.
So some help would be much appreciated, thanks a lot :)
The easiest approach is to create a function which initialises the struct:
void init_course(struct course* c, const char* id, int num_nodes)
{
strncpy(c->identifier, id, sizeof(c->identifier));
c->num_nodes = num_nodes;
c->nodes = calloc(num_nodes, sizeof(struct node));
}
For symmetry, you could also then define a destructor
void destroy_course(struct course* c)
{
free(c->nodes);
}
These would have usage like
struct course c;
init_course(&c, "AA", 5);
/* do stuff with c */
destroy_course(&c);
The purpose of malloc (or calloc - which I prefer to use for structs) is to dynamically allocate the memory at runtime. So, your struct should look like this, since it is an object definition:
struct course {
char identifier[2];
int num_nodes;
struct node *nodes;
};
Somewhere else in your program that uses the course struct, you will need to allocate memory (i) for any course objects you create and (ii) any node objects in that course.
e.g.
main()
{
// lets say 1 course
struct course *my_course;
my_course = calloc(1, sizeof(struct course));
// lets say 3 nodes in that course
struct node *my_nodes;
my_nodes = calloc(3, sizeof(struct node));
my_course.num_nodes = 3;
my_course.nodes = my_nodes;
//...
// clean up
free(my_nodes);
free(my_course);
}
Now, you are good. Make sure to free the memory before exiting.
it is also possible to direct allocate the structs in structs this way:
first declare your struct:
struct course {
char identifier[2];
int num_nodes;
struct node *nodes;
};
then in your program
main(){
int i;
struct course *c;
c = malloc(sizeof(struct course));
c->num_nodes = 3;
c->nodes = malloc(sizeof(struct node)*c->num_nodes);
for(i=0; i<c->num_nodes; i++)
c->nodes[i] = malloc(sizeof(struct node));
//and free them this way
for(i=0; i<c->num_nodes; i++)
free(c->nodes[i]);
free(c->nodes);
free(c);
}
or do it the way above what ever you like
I'm not sure exactly what I need to use as an argument to malloc to allocate space in the table_allocate(int) function. I was thinking just count_table* cTable = malloc(sizeof(count_table*)), but that doesn't do anything with the size parameter. Am I supposed to allocate space for the list_node_t also? Below is what I am working with.
In the .h file I'm given this signature:
//create a count table struct and allocate space for it
//return it as a pointer
count_table_t* table_allocate(int);
Here are the structs that I'm supposed to use:
typedef struct list_node list_node_t;
struct list_node {
char *key;
int value;
//the next node in the list
list_node_t *next;
};
typedef struct count_table count_table_t;
struct count_table {
int size;
//an array of list_node pointers
list_node_t **list_array;
};
count_table* cTable = malloc(sizeof(count_table*))
is wrong. It should be
count_table* cTable = malloc(sizeof(count_table));
Also, you must allocate memory for list_node_t also seperately.
EDIT:
Apart from what Clifford has pointed about allocating memory for the list node, I think the memory allocation should also be taken care for the char *key inside of the list node.
Your suggestion: count_table* cTable = malloc(sizeof(count_table*)) would only allocate space for a pointer to a count_table.
You'd need
count_table* cTable = malloc(sizeof(count_table) ) ;
Each list node would be separately allocated and cTable->size and cTable->list_array and the last list_node_t::next updated accordingly. Maintaining a pointer to the last node added would make adding nodes faster.
I am not sure why count_table::list_array is of type list_node_t** rather than just list_node_t* (and equally called list_array rather than just list). Is it your intention that it is both an array and a list at the same time? That would be somewhat redundant. The member need only be a pointer to the first node, successive nodes are then accessed via list_node::next
Given that the int is a "size" parameter for the created count_table_t, it appears that you are supposed to both allocate the count_table_t itself, as well as initialise its members.
Initialising the list_array member also involves a memory allocation, so it would look like:
count_table_t *table_allocate(int size)
{
count_table_t *table = malloc(sizeof *table);
int i;
table->size = size;
table->list_array = malloc(size * sizeof table->list_array[0]);
for (i = 0; i < size; i++)
table->list_array[i] = NULL;
return table;
}
However, you also need to check for some error conditions: the multiplication of size by sizeof table->list_array[0] could overflow, and either of the malloc() calls could fail. So the function should actually look like this:
count_table_t *table_allocate(int size)
{
count_table_t *table;
int i;
/* Check for overflow in list allocation size */
if (size < 0 || size > (size_t)-1 / sizeof table->list_array[0])
return NULL;
table = malloc(sizeof *table);
if (table == NULL)
return NULL;
table->size = size;
table->list_array = malloc(size * sizeof table->list_array[0]);
if (table->list_array == NULL) {
free(table);
return NULL;
}
for (i = 0; i < size; i++)
table->list_array[i] = NULL;
return table;
}
(Note that (size_t)-1 is a constant equal to the maximum value of a size_t, which is the type of the parameter to malloc()).
In addition to the other posters who point out that you're only allocating enough space for the pointer, not the space the data you want will occupy, I strongly urge you to do things like this:
count_table* cTable = malloc(sizeof(*cTable));
This will help you in case the type of cTable ever changes, you won't have to adjust two parts to that line, just the type.