Memory allocation problem in HashTable
Please do not cover this statement with a repetitive question . I made an important change so as not to confuse people, I reintroduced these clearer codes.
Please help me solve this memory allocation problem. I am working on HashTable and this is what I have (partial codes only)
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;
hash->list = (ListPtr *)calloc(capacity, sizeof(List)); /*NO MEMORY ALLOCATION HERE*/
return hash;
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 (Netbeans C / C ++ debugger, I don't see the memory not being put into the hash-> list. In the above example, my attempt is to make an array of 10 lists.
Please help me to solve this problem.
I'm not a C expert if that helps.
This line
hash = (HashTablePtr) malloc(sizeof(HashTablePtr));
must read
hash = (HashTablePtr) malloc(sizeof(HashTable));
I also suggest that you follow the advice given to you in a previous post and DO NOT hide pointers by typedef'ing. Just useList *
[Whenever you see an alloc statement, the type you assign is a pointer, and the type you allocate must be of a type (not a pointer to a type)]
a source to share
Nice idiom you can use, for example:
hash = (HashTablePtr) malloc(sizeof(*hash));
By not hard-coding any types in the distribution, the possibility of mixing things is greatly reduced.
Note that "hash" is not actually dereferenced here. sizeof () is always evaluated at compile time, so the compiler just determines the type * hash / would / have and gets the size of that.
a source to share
In this line:
hash->list = (ListPtr *)calloc(capacity, sizeof(List));
The function calloc
will allocate some memory for List
, then return a pointer to the allocated memory, which will be List*
(or equivalent ListPtr
due to typedef
.)
In the code, the pointer is then called to (ListPtr*)
, which in fact would be List**
, which is not the type List*
that is expected. So change the value ListPtr*
to ListPtr
and see if that fixes that line.
Edit
As Leise and Klatzazt point out in the comments, type Hashtable.list
ListPtr*
or List**
:
struct hashtable {
...
ListPtr *list;
That would be the reason that trying to assign the type ListPtr
returned and derived from calloc
would result in a compiler error. Instead of storing a pointer to a list pointer in Hashtable
, it should just hold a pointer to a list:
struct hashtable {
...
ListPtr list;
This should rule out a compiler error as the type Hashtable.list
and typecast will be ListPtr
.
a source to share
Personally, I'm not a big fan of using typedefs, especially when you're a beginner. I think this may be partially confusing for you. You are better off avoiding things like:
typedef struct hashtable * HashTablePtr;
Using typedefs in many will make your code harder to read, as you have to constantly look for what they refer to.
The main problem is that you were allocating memory for the size of the hashtable / list pointer, not the size of their respected structures. I think the code below shows this well. You will also want to check if you worked. If malloc, calloc, realloc. and so on, they don't return NULL. If this happens, and you don't check this case, you will get a segfault error and your program will crash.
Also follow the c99 standard and put all variable declarations at the beginning of the function.
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 the list before freeing the hash table:
free(myhash->list);
free(myhash);
a source to share