Where is the error in freeing memory from created hashtable - c

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.

Related

how to check if the pointer of a particular data structure is pointing to another node of the same data structure

This is the structure I defined for my B+ Tree. The function I display returns the number of the not NULL pointers of a node. The problem I'm encountering is that one of the pointers is pointing to:
7:i = 4
8: node->pointer[i] = (struct bptree *) 0x1
when checked in gdb which is neither a NULL pointer or a pointer to a Bptree node. When actually the answer should be 3. So is there a way to see if the pointer is pointing a Bptree structure or any data structure it is supposed to point to. N is the order of the B+ Tree
struct bptree
{
char **key;
int nokeys;
struct bptree* pointer[N];
int root;
int leaf;
struct bptree* parent;
};
typedef struct bptree Bptree;
int noofpointers(Bptree *node)
{
int i = 0;
if(node == NULL)
return i;
while(node->pointer[i] != NULL)
i++;
return i;
}
Not in general, no. Pointers don't carry any additional meta information besides their value, at run-time. You cannot inspect memory and figure out what it is holding (you can try by decorating your data with magic numbers).
Also, your code is scary since if all the pointers are used, it will run out of bounds. You must make sure i is less than N in the loop, and exit when all pointers have been checked.

C type * (blank) declaration (binary tree, case in point)

Here is a piece of code that's confusing me.
struct tNode {
int key; // search key for this item
int data; // data for this item
struct tNode *left, *right; // children
};
typedef struct tNode tree_type;
/**************** tree_new() ****************/
/* Create a new tree */
tree_type *
tree_new(const int key, const int data)
{
tree_type *node = malloc(sizeof(struct tNode));
...
}
}
So I'm not quite getting the syntax for tree_type * right above tree_new function. Doesn't seem like a pointer... not sure what it's doing there.
--------------------- post-edit
Thanks to all who helped out!
You have to read both lines together:
tree_type *
tree_new(const int key, const int data)
is just another legal way to write the function definition with its return type:
tree_type *tree_new(const int key, const int data)
since it doesn't end with a semicolon, the statement continues on the next line(s).
tree_type * is not a blank declaration. tree_type is a declaration specifier and * is the part of the declarator for the function tree_new (Thanks to #Jonathan Leffler for the nitpick).
That says, tree_type * depicts the return type of the function tree_new.
int *foobar(int x) {
return 42;
}
is the same as
int *
foobar(int x)
{
return 42;
}
Same thing with tree_type (or struct tNode).
Your use of pointers look fine. Your malloc() returns a pointer to memory to a defined pointer type. After seeing your small code, I thought you might benefit with suggestions for it and the context your binary tree example might be used in.
typedef nameing convention
Struct declaration and typedef can be done at the same time. That's a matter of preference. A common convention for typedefs in C is to name it in the form someType_tto have a consistent way of identifying typedefs everywhere they're used.
Zeroing allocated memory
I usually use calloc(), rather than malloc() because unlike malloc(), calloc() zeroes the allocated memory.
I might add the word _safe to the name of the allocation function (by convention), to indicate if it returns, it has succeeded (e.g. it's safe so a null-check in the calling layer is unnecessary).
Safe allocation and checking for allocation failures
The allocation does the null check and displays an explicit simple out-of-memory message if there isn't enough memory available. If the program is out of memory anywhere, that an usually be considered fatal and a justification to exit the program, because, if there isn't enough memory anywhere, things are likely to be failing everywhere. It would be a very rare program that has the sophistication to handle an out of memory condition robustly, such as being able to wait it out and retry until memory is available again, so simply exiting is common. Using safe allocation functions will save you a lot of null-checking in the calling layer.
Setting freed pointers to NULL
Note the setting of the freed pointer to NULL. If this is done consistently then a pointer can always be determined to be valid or not by a NULL check. Further, freeing NULL on most systems is a NOP, so in that way you can lower the risk of double free (freeing a pointer more than once), which can produce some disastrous and difficult to diagnose bugs, particularly in larger programs.
Simple Binary Tree Example
(compiles/runs)
#include <stdio.h>
#include <stdlib.h>
typedef struct Tree {
int key;
int data;
struct Tree *left, *right;
} tree_t;
// Dummy data just for example:
#define KEY 1
#define VAL 2
#define KEY2 3
#define VAL2 4
#define KEY3 5
#define VAL3 6
tree_t *node_create_safe(const int, const int);
void free_tree(tree_t *);
int
main() {
tree_t *rootNode = node_create_safe(KEY, VAL);
rootNode->left = node_create_safe(KEY2, VAL2);;
rootNode->right = node_create_safe(KEY3, VAL3);;
free_tree(rootNode);
rootNode = NULL;
}
/*
* node_create_safe() - allocates node, always returns pointer.
*
* Side effects: Terminates program on allocation failure.
*/
tree_t *
node_create_safe(const int key, const int data) {
tree_t *node = calloc(sizeof(struct Tree), 1);
if (node == NULL) {
fprintf(stderr, "out of memory\n");
exit(-1);
}
node->key = key;
node->data = data;
return node;
}
/*
* free_tree() - Recursively frees [sub]tree
*/
void
free_tree(tree_t *node) {
if (node->left != NULL)
free_tree(node->left);
if (node->right != NULL)
free_tree(node->right);
free(node);
}

Memory allocation of fixed size array inside a struct

I have the following tree node struct that holds pointers to other tree nodes:
struct node {
// ...
struct node* children[20];
}
The idea is that I want to check whether there is node* inside the children and based and that go deeper into the tree. So when I allocate the node I want to have children with 20 NULL values.
Currently I am not doin
How should I allocate this array in order to not get errors like Conditional jump or move depends on uninitialised value(s) (Valgrind)?
Would it be better to use struct node** children and allocate fixed size each time I allocate a new node?
EDIT: Example of one place where Valgrind complains:
for(int i=0;i<20;i++)
if(node->children[i] != NULL)
do_something_with_the_node(node->children[i]);
When you allocate a new instance of struct node, you must set the contained pointers to NULL to mark them as "not pointing anywhere". This will make the Valgrind warning go away, since the pointers will no longer be uninitialized.
Something like this:
struct node * node_new(void)
{
struct node *n = malloc(sizeof *n);
if(n != NULL)
{
for(size_t i = 0; i < sizeof n->children / sizeof *n->children; ++i)
n->children[i] = NULL;
}
return n;
}
You cannot portably use either memset() on n->children nor calloc(), since those will give you "all bits zero" which is not the same as "pointer NULL".
Your struct definition is valid (although it's hard to tell without more context if it fits your requirements).
Valgrind doesn't complain about your struct definition, it probably complains about how you instantiate variables of that type. Ensure that all of the array members get initialized and the complaints will most likely go away.
The problem is that you are using an unintialized value in an if condition.
When you instantiate a struct node, its member struct node* children[20]; is an array of 20 struct node *, all of which are uninitialized.
It would be no different from this:
char *x;
if (x == NULL) {
/* Stuff */
}
At this point, x may have literally any value. In your example, any element of an array may have any value.
To fix this, you need to initialize the elements of an array before using them, for example like this:
for (int i = 0; i < 20; ++i) {
node->children[i] = NULL;
}
Or shorter:
memset(node->children, 0, 20);
If you changed the member to, as you've suggested, node **children, the situation wouldn't be much different - you'll still need to initialize all the members, including array's elements. You could make it shorter by using calloc, which will initialize all bytes to 0; then again, you'll need some code for correct deallocation (and remember to do it), so I think the tradeoff's not worth it.

Singly Linked List in C incorrect output

So I'm doing some linked list revison and Im trying to just load a list with some numbers and then print it out. Below is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct stack {
int data;
struct stack *next;
}*stack;
stack create_s(void){
stack s = (void*)malloc(sizeof(stack));
s->next = NULL;
return s;
}
void push_s(stack s, int data) {
while (s->next != NULL) {
s = s->next;
}
s->next = (void*)malloc(sizeof(stack));
s=s->next;
s->data = data;
s->next = NULL;
}
void print_s(stack s) {
if (s==NULL) {
return;
}
else {
while (s->next != NULL) {
printf("%d\n",s->data);
s=s->next;
}
}
}
int main (void) {
stack s = create_s();
push_s(s,2);
push_s(s,4);
push_s(s,6);
push_s(s,8);
print_s(s);
return 0;
}
My output is however:
-1853045587
2
4
6
when it should be
2
4
6
8
Is it printing the address of my struct at the beginning? Also, why is it not printing my last element?
Thanks
The code contains several errors, but the first thing that catches the eye is that your memory allocation is already obviously broken
stack s = (void*)malloc(sizeof(stack));
You defined stack as a pointer type. This means that sizeof(stack) evaluates to pointer size and the above malloc allocates enough space to store a single pointer, not enough for the entire struct stack object. The same memory allocation error is present in push_s as well.
Here's some advice
Don't hide pointer types behind typedef names. Define your stack as
typedef struct stack{
int data;
struct stack *next;
} stack;
and use stack * wherever you need a pointer. I.e. make that * visible instead of hiding it "inside" a typedef name. This will make your code easier to read.
Don't cast the result of malloc. Anyway, what is the point of casting it to void * when it is void * already???
Don't use sizeof with types unless you really really have to. Prefer to use sizeof with expressions. Learn to use the following malloc idiom
T *p = malloc(sizeof *p);
or, in your case
struct stack *s = malloc(sizeof *s);
This will allocate a memory block of appropriate size.
Also, as #WhozCraig noted in the comments, the very first node in your list is apparently supposed to serve as a "sentinel" head node (with undefined data value). In your code you never initialize the data value in that head node. Yet in your print_s function you attempt to print data value from the head node. No wonder you get garbage (-1853045587) as the first line in your output. Don't print the very first node. Skip it, if it really is supposed to serve as a sentinel.
Also, the cycle termination condition in print_s looks strange
while (s->next != NULL)
Why are you checking s->next for NULL instead of checking s itself? This condition will terminate the cycle prematurely, without attempting to print the very last node in the list. This is the reason why you don't see the last element (8) in your output.
The actual cause of the given output can be fixed by changing:
s=s->next;
s->data = data;
to
s->data = data;
s=s->next;

A hashtable of pointers in C?

I am trying to build an initialize a hashtable whose pointers point to another struct in my program. But it seems to give me a segfault when I try to initialize(H). I think I may be allocating memory incorrectly, but I'm not sure if that's what a segmentation fault actually means. The way it is set up, H->hashtable should be an array of hashnodes, right? hashnodes themselves are the pointers to my other structs. Why am I only getting a seg fault at initialize?
#include <stdio.h>
#include <stdlib.h>
typedef struct Position{
char data[12];
struct Hashnode *previous;
struct Position *next;
char letter;
char direction[5];
} *position;
typedef struct Hashnode{
struct Position *INSIDE;
} *hashnode;
typedef struct hash_table{
hashnode *hashtable
} *HTABLE;
HTABLE NewHashtable(){
HTABLE H = (HTABLE) malloc(sizeof(struct hash_table));
if(H == NULL){ printf("Malloc for new hashtable failed."); exit(1);}
return H;
}
void initialize(HTABLE H){
H->hashtable = (hashnode*) malloc(100003*sizeof(hashnode));
int toofer;
for(toofer = 0; toofer<100003; toofer++){
H->hashtable[toofer]->INSIDE = NULL;
}
}
int main(){
HTABLE H = NewHashtable();
initialize(H);
return 0;
}
This:
HTABLE H = (HTABLE) malloc(sizeof(struct hash_table));
is just horrible. It mixes a typedef:ed pointer (why do people still do this?) with the underlying struct name, making it the reader's job to make sure they match. Plus, that cast is a bad idea, too.
It should be:
HTABLE H = malloc(sizeof *H);
if you insist on keeping the typedef.
That said, the code in initialize() is probably failing its malloc() call, which is not checked before being relied on. This is a very bad idea.
Further, there's confusion about what exactly is being allocated. The malloc() code allocates 100003*sizeof(hashnode), but hashnode is (again) typedef:ed as a pointer, not a struct. Then the pointers are dereferenced in the loop, causing mayhem.
H->hashtable = (hashnode*) malloc(100003*sizeof(hashnode));
int toofer;
for(toofer = 0; toofer<100003; toofer++){
H->hashtable[toofer]->INSIDE = NULL;
}
}
The first line allocates a bunch of memory for H->hashtable. It contains random garbage.
Thus, when you enter the loop, H->hashtable[0] is random garbage (because all of H->hashtable is random garbage). But you attempt to follow that random garbage pointer in in your loop. Dereferencing an uninitialized pointer is the fastest way to get a segmentation fault.
Here's a way to help you see it. Say you decided to zero that memory to be safe. Your code would be:
H->hashtable = (hashnode*) malloc(100003*sizeof(hashnode));
memset(H->hashtable, 0, 100003 * sizeof(hashnode));
int toofer;
for(toofer = 0; toofer<100003; toofer++){
H->hashtable[toofer]->INSIDE = NULL;
}
}
Clearly, after that memset, *(H->hashtable) is 0 since that sets all of H->hashtable to 0. So H->hashtable[0] is 0 too and thus H->hashtable[toofer]->INSIDE dereferences a null pointer.
H->hashtable = (hashnode*) malloc(100003*sizeof(hashnode));
should better be
...sizeof(struct Hashnode)...

Resources