Breakpoint triggered when freeing a pointer - c

I'm writing a binary search tree for a class and I probably am doing something wrong but it's beyond my skill to determine what.
Here's the node structure:
typedef struct Node {
int value;
struct Node *left;
struct Node *right;
} Node, *NodePtr;
Here's my create node function:
NodePtr nodeCreate(int value) {
NodePtr node_new = 0;
node_new = (NodePtr) malloc(sizeof node_new);
node_new->value = value;
node_new->left = 0;
node_new->right = 0;
return node_new;
}
And my destroy the whole tree function:
void treeDestroy(NodePtr root) {
if (!root) { return; }
treeDestroy(root->left);
treeDestroy(root->right);
free(root); // HERE IS WHERE MY BREAKPOINT TRIGGERS
root = 0;
}
Finally here's what my main looks like:
int main(int argc, char *argv[]) {
NodePtr tree_root = 0;
tree_root = nodeCreate(2);
tree_root->left = nodeCreate(1);
tree_root->right = nodeCreate(3);
treePrint(tree_root);
treeDestroy(tree_root);
return 0;
}
Can anyone help me find what's wrong there?

node_new = (NodePtr) malloc(sizeof node_new);
should be
node_new = malloc(sizeof *node_new);
sizeof node_new is size of pointer where as sizeof *node_new is size of object which pointer is pointing.

Related

C Language - Rehashing a Separate Chaining Hash Table

So I looked everywhere to get inspired but I didn't really find anything for rehashing a hash table using separate chaining method. So I tried myself, I think I know what I'm doing wrong, but I don't know how else to implement it, please help.
Everything works, except the new added function rehash()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
struct list_node
{
struct list_node *next;
char *key;
char *value;
};
struct hash_table
{
int table_size;
struct list_node **list_arr;
};
unsigned int hash(const char *key, unsigned int table_size);
struct hash_table *initialize(unsigned int table_size);
struct list_node *find(struct hash_table *H, const char *key);
void insert(struct hash_table *H, const char *key, const char *value);
void dump(struct hash_table *H);
void del(struct hash_table *H, const char *key);
struct hash_table *rehash(struct hash_table *H);
unsigned int
hash(const char *key, unsigned int table_size)
{
unsigned long int hashx = 0;
for(int i=0;key[i];i++)
{
hashx = (hashx<<5) + key[i];
}
return (hashx%table_size);
}
struct hash_table
*initialize(unsigned int table_size)
{
struct hash_table *H = malloc(sizeof(*H));
H->list_arr = malloc(sizeof(*H->list_arr)*table_size);
H->table_size = table_size;
for(unsigned int i = 0; i<table_size; i++)
{
H->list_arr[i] = malloc(sizeof(*H->list_arr[i]));
H->list_arr[i]->next = NULL;
}
return H;
}
void
insert(struct hash_table *H, const char *key, const char *value)
{
unsigned int index = hash(key, H->table_size);
struct list_node *head = H->list_arr[index];
struct list_node *current = head->next;
while(current!=NULL)
{
if(strcmp(current->key,key)==0)
{
free(current->value);
current->value = malloc(strlen(value)+1);
strcpy(current->value,value);
return;
}
current=current->next;
}
struct list_node *newNode = malloc(sizeof(*H->list_arr[index]));
newNode->next = head->next;
head->next = newNode;
newNode->key = malloc(strlen(key)+1);
newNode->value = malloc(strlen(value)+1);
strcpy(newNode->key,key);
strcpy(newNode->value,value);
}
void
dump(struct hash_table *H)
{
for( int i = 0; i<H->table_size; i++)
{
struct list_node *entry = H->list_arr[i]->next;
if(entry==NULL){continue;}
printf("Index[%d]: ", i);
while(entry!=NULL)
{
printf("\t%s|%s\t--> ", entry->key, entry->value);
entry = entry->next;
}
printf("\tNULL");
printf("\n");
}
}
void delete(struct hash_table *H, const char *key)
{
unsigned int index = hash(key,H->table_size);
struct list_node *prev = H->list_arr[index];
while(strcmp(prev->next->key,key)!=0)
{
if(prev->next==NULL){printf("Key not found!");return;}
prev=prev->next;
}
struct list_node *temp = prev->next;
prev->next = temp->next;
free(temp);
}
struct hash_table *rehash(struct hash_table *H)
{
unsigned int old_size = H->table_size;
struct list_node *old_entries = H->list_arr;
H = initialize(2*old_size);
for(unsigned int i = 0; i<old_size; i++)
{
while(old_entries[i]!=NULL)
{
insert(H,old_entries[i].key,old_entries[i].value);
old_entries[i] = old_entries[i]->next;
}
}
free(old_entries);
return H;
}
int main()
{
struct hash_table *H = initialize(20);
insert(H,"name1","David");
insert(H,"name2","Radka");
dump(H);
H = rehash(H);
dump(H);
return 1;
}
I think doing old_entries[i] is wrong, but nothing else comes to mind, please help me resolve this.
OK! After thinking about it for a while, I realized I created a struct list_node pointer variable that points to H->list_arr which is an array of pointers. That was my mistake. I was supposed to declare it as a double pointer.
Here's the modified rehash() function:
struct hash_table *rehash(struct hash_table *H)
{
unsigned int old_size = H->table_size;
struct list_node **old_entries = H->list_arr;
H = initialize(2*old_size);
for(unsigned int i = 0; i<old_size; i++)
{
old_entries[i] = old_entries[i]->next;
while(old_entries[i]!=NULL)
{
insert(H,old_entries[i]->key,old_entries[i]->value);
old_entries[i] = old_entries[i]->next;
}
}
free(old_entries);
return H;
}
with this code, you will have to return the address of the new hash_table to the pointer pointing to the old hash_table --> [H = rehash(H)] since passing the pointer H as a parameter will only change it locally. Therefore, I tried a second version (because I'm too lazy;) and inattentive and might forget to reassign it) where I don't have to return anything, I want to change it simply by calling the function and my pointer points to the new hash_table automatically -> [rehash(&H)], here's the other "lazy" alternative:
void
rehash(struct hash_table **H)
{
unsigned int old_size = (*H)->table_size;
struct list_node **old_entries = (*H)->list_arr;
*H = initialize(2*old_size);
for(unsigned int i = 0; i<old_size; i++)
{
old_entries[i] = old_entries[i]->next;
while(old_entries[i]!=NULL)
{
insert(*H,old_entries[i]->key,old_entries[i]->value);
old_entries[i] = old_entries[i]->next;
}
}
free(old_entries);
}
If I'm doing something that's inefficient (in terms of space and time), please let me know, as I am only in Bachelor's 3rd semester of CS and we have only started DSA this semester.
The thing you are doing by putting dummy elements at the beginning of each bin is a good idea, but you don't need to allocate such dummies with malloc(). You can just make the bin array an array of nodes instead of pointers to nodes. Then you have allocated the dummies when you have allocated the array. So you could define your hash table as
struct hash_table
{
int table_size;
struct list_node *list_arr;
};
(instead of using struct list_node **list_arr).
When you loop through the bins in the initialisation, you have to set the bins' next pointer to NULL, but not allocate them.
struct hash_table
*initialize(unsigned int table_size)
{
struct hash_table *H = malloc(sizeof(*H));
H->list_arr = malloc(sizeof(*H->list_arr)*table_size);
H->table_size = table_size;
for(unsigned int i = 0; i<table_size; i++)
{
// no malloc here!
H->list_arr[i].next = NULL;
}
return H;
}
Anyway, that is not pertinent to the rehashing, just a suggestion. But because you have the dummy elements as bins, you can refactor your code (that is the reason I think the dummies are such a good idea). You can get the bin from the table and work from there, without worrying about the table itself after that. You can get the relevant bin for a key with
struct list_node *get_bin(struct hash_table *H, const char *key)
{
unsigned int index = hash(key, H->table_size);
return &H->list_arr[index];
}
and you can find the node in a bin with
struct list_node *find_node(struct list_node *bin, const char *key)
{
for (struct list_node *current = bin->next;
current;
current = current->next) {
if(strcmp(current->key,key)==0) return current;
}
return 0;
}
and, for example, simplify insertion to
void prepend_node(struct list_node *node, struct list_node *bin)
{
node->next = bin->next;
bin->next = node;
}
void insert(struct hash_table *H, const char *key, const char *value)
{
struct list_node *bin = get_bin(H, key);
struct list_node *node = find_node(bin, key);
if (node) {
// update node
free(node->value);
node->value = malloc(strlen(value)+1);
strcpy(node->value,value);
} else {
// prepend new node
prepend_node(new_node(key, value), bin);
}
}
where the new_node() function looks like
struct list_node *new_node(const char *key, const char *value)
{
struct list_node *node = malloc(sizeof *node);
if (!node) abort(); // add some error handling here
node->key = malloc(strlen(key)+1);
if (!node->key) abort(); // add some error handling here
strcpy(node->key,key);
node->value = malloc(strlen(value)+1);
if (!node->value) abort(); // add some error handling here
strcpy(node->value,value);
return node;
}
Because the bins are embedded in the array, you can safely assume in all the functions that they aren't NULL, which can save you from testing some special cases.
It is not shorter code, because I split it into several functions, but in my opinion, it is more readable when each function does one simple thing. Here, getting the bin, finding the key in a bin, creating a node, pretending to a bin, etc. With "raw" malloc() and strcpy() and such, scattered through the code, it is harder to track that everything works correctly. The total lines of code grew, but each function is shorter and simpler. And you can get away with it, because you can work on bins as lists, without accessing the hash table array, exactly because all bins have a dummy head element.
You can now rewrite rehash() to just prepend to bins. You know that all the keys in the old bins are unique, so you don't need to check anything. You just put each node at the front of its new bin:
struct hash_table *rehash(struct hash_table *H)
{
unsigned int old_size = H->table_size;
struct list_node *old_entries = H->list_arr;
free(H); // You forgot to free this one!
H = initialize(2*old_size);
for(unsigned int i = 0; i<old_size; i++)
{
struct list_node *old_bin = &old_entries[i];
for (struct list_node *node = old_bin->next;
node; node = node->next) {
// just prepend to new bin; the key should be unique
prepend_node(node, get_bin(H, node->key));
}
}
free(old_entries);
return H;
}
I added a free(H) because you forgot to free memory for H, but it would be more efficient to update H without creating a new table. You can separate initialisation and allocation. But you do not gain terribly much as initialising the bins is the time-consuming part.
Speaking of freeing, though. Remember to write a function for freeing a hash table (that remembers to free the bins, including all the nodes). Don't use it with rehashing, of course, if you free H before you update it--you need to keep the nodes around--but you do want such a function.

How to make changes in an array through a function

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 10
// A hashtable is a mixture of a linked list and array
typedef struct node NODE;
struct node{
int value;
NODE* next;
};
int hash(int);
void insert(int,NODE **);
int main(){
NODE* hashtable[SIZE];
insert(12,&hashtable[SIZE]);
printf("%d\n",hashtable[5]->value);
}
int hash(int data){
return data%7;
}
void insert(int value,NODE **table){
int loc = hash(value);
NODE* temp = malloc(sizeof(NODE));
temp->next = NULL;
temp->value = value;
*table[loc] = *temp;
printf("%d\n",table[loc]->value);
}
The above code prints :
12 and
27475674 (A random number probably the location.)
how do I get it to print 12 and 12 i.e. how to make a change in the array. I want to fill array[5] with the location of a node created to store a value.
The expression *table[loc] is equal to *(table[loc]) which might not be what you want, since then you will dereference an uninitialized pointer.
Then the assignment copies the contents of *temp into some seemingly random memory.
You then discard the memory you just allocated leading to a memory leak.
There's also no attempt to make a linked list of the hash-bucket.
Try instead to initially create the hashtable array in the main function with initialization to make all pointers to NULL:
NODE* hashtable[SIZE] = { NULL }; // Will initialize all elements to NULL
Then when inserting the node, actually link it into the bucket-list:
temp->next = table[loc];
table[loc] = temp;
This is just a simple change which I have made to your program which will tell you what you are actually doing wrong.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 10
// A hashtable is a mixture of a linked list and array
typedef struct node NODE;
struct node {
int value;
NODE* next;
};
NODE *hashtable[SIZE] = { NULL };
int hash(int);
int insert(int); //, NODE **);
int main(void)
{
int loc = insert(12); //, &hashtable[SIZE]);
if (loc < SIZE) {
if (hashtable[loc]) {
printf("%d\n", hashtable[loc]->value);
} else {
printf("err: invalid pointer received\n");
}
}
return 0;
}
int hash(int data)
{
return data%7;
}
int insert(int value) //, NODE *table[])
{
int loc = hash(value);
printf("loc = %d\n", loc);
if (loc < SIZE) {
NODE *temp = (NODE *) malloc(sizeof(NODE));
temp->value = value;
temp->next = NULL;
hashtable[loc] = temp;
printf("%d\n", hashtable[loc]->value);
}
return loc;
}
Here I have declared the hashtable globally just to make sure that, the value which you are trying to update is visible to both the functions. And that's the problem in your code. Whatever new address you are allocating for temp is having address 'x', however you are trying to access invalid address from your main function. I just wanted to give you hint. Hope this helps you. Enjoy!

Correct Freeing double-linked nodes in C language

I'm pretty new to C world and I don't know how is the correct way to delete this data structure avoiding memory leaks and segmentation faults.
The data structure is this:
typedef struct Node {
int id;
struct Node *parent; /* node's parent */
struct Node *suffix_node;
int first_char_index;
int last_char_index;
bool is_leaf;
struct Node **children; /* node's children */
int children_size; /* size of children structure */
int children_count; /* # of children */
int depth;
}Node;
typedef struct SuffixTree {
Node *root;
int nodes_count;
char *string;
}SuffixTree;
What I would do is, from a pointer to SuffixTree structure, freeing entirely tree.
I have tried to do this:
void deleteSubTree(Node *nd)
{
if (nd->is_leaf)
{
free(nd->children);
free(nd);
return;
}
int i = 0;
for(;i < nd->children_count; ++i)
{
deleteSubTree(nd->children[i]);
}
free(nd->children);
free(nd);
return;
}
void deleteSuffixTree(SuffixTree *st)
{
deleteSubTree(st->root);
free(st);
}
But it is not correct.
EDIT:
This is main:
int main()
{ char *str = "BOOK\0";
SuffixTree *st = createSuffixTree(str);
deleteSuffixTree(st);
return 0;
}
And this is how I allocate tree and nodes:
Node* createNode(){
Node *stn = (Node*)malloc(sizeof(Node));
stn->id = node_id++;
stn->parent = (Node*)malloc(sizeof(Node));
stn->suffix_node = (Node*)malloc(sizeof(Node));
stn->first_char_index = -1;
stn->last_char_index = -1;
stn->children_size = NODE_BASE_DEGREE;
stn->children_count = 0;
stn->children = (Node**)malloc(stn->children_size*sizeof(Node*));
stn->is_leaf = true;
stn->depth = 1;
return stn;
}
SuffixTree* createSuffixTree(char *str)
{
SuffixTree *st = (SuffixTree*)malloc(sizeof(SuffixTree));
st->root = createNode();
st->root->parent = (Node*)malloc(sizeof(Node));
st->root->parent->id = -1;
st->nodes_count = 1;
st->string = str;
makeTreeWithUkkonen(st);
return st;
}
makeTreeWithUkkonen is correct, I can display correct tree after createSuffixTree() call.
As GeoMad89 said, you malloc already existing nodes in the createNode() method.
If you change your createNode() code into this:
Node* createNode(Node* parent, Node* suffixNode){
Node *stn = (Node*)malloc(sizeof(Node));
stn->id = node_id++;
stn->parent = parent; //(Node*)malloc(sizeof(Node));
if(suffixNode != NULL)
stn->suffix_node = suffixNode; //(Node*)malloc(sizeof(Node));
stn->first_char_index = -1;
stn->last_char_index = -1;
stn->children_size = NODE_BASE_DEGREE;
stn->children_count = 0;
stn->children = (Node**)malloc(stn->children_size*sizeof(Node*));
if(parent != NULL){
parent->children[parent->children_count++] = stn;
parent->is_leaf = false;
}
stn->is_leaf = true;
stn->depth = 1;
return stn;
}
And if you try it with valgrind, using this toy main:
main(int argc, char** argv){
Node* root = createNode(NULL, NULL);
Node* node1 = createNode(root, NULL);
Node* node2 = createNode(root, NULL);
Node* node3 = createNode(node1, NULL);
deleteSubTree(root);
return 0;
}
You will see that all the malloc'd memory will be freed!
Needless to say, this code works only with NODE_BASE_DEGREE=2, otherwise, if you use a greater NODE_BASE_DEGREE value, you have to realloc the children array.
I have noticed that the leaf nodes have their children array not empty, because children_size is equal to NODE_BASE_DEGREE.
Try to delete the elements of the array in the leaves before eliminating them.
I have noticed two possible memory leaks:
In createNode, i suppose that the parent of the node that you going to create already exist, there is no need to malloc a space for it. But anyway you change the value of the pointer of parent in createSuffixTree, at least in the root of the tree, so this memory that you have allocated in createNode for parent is lost.
I don't know what suffix_node is, if is a node of the tree there is the same problem of the point one. But if is another node and so it is correct allocate memory, you don't freed when deleted the tree.

How to point to a pointer variable

Is there a way to point to the pointer variable instead of it's address space so that it can be changed to NULL. Something like this. Apologies for the poor question I can't think of a better way of expressing what I'm trying to do.
Thanks.
typedef struct Node
{
int val;
struct Node *r;
struct Node *l;
} Node;
Node* del(Node *N, int v)
{
Node *n = N;
Node **p = NULL;
while (n != NULL)
{
if (something)
{
p = n.r;
n = n->r;
}
else {
p = n.l;
n = n->l;
}
free(n);
*p = NULL;
}
}
You can use & on a pointer just like on any other variable. In your case, it looks like you might want to change del to:
Node *del(Node **N, int v)
And then call it like:
x = del(&someNode, 12);

pointer problem in implementing Tree in C

I am implementing an avl tree for my assignment.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
struct TreeNode {
char *item;
struct TreeNode *left;
struct TreeNode *right;
signed char balance;
};
typedef struct TreeNode Node;
void _print_avl (Node *, int , const char *);
Node * get_new_node (char *);
int avl_insert(Node *, char *);
void print_avl (Node *);
void avl_swr(Node*);
int main (int argc, char *argv[])
{
Node *root = get_new_node("thura");
avl_insert(root, "thur2");
print_avl(root);
avl_insert(root, "thur1");
return 0;
}
int avl_insert(Node *root, char *item)
{
assert(root);
if( strcmp(item, root->item) < 0) {
if(!root->left) {
root->left = get_new_node(item);
if(--(root->balance)) return 1;
return 0;
} else {
if(avl_insert(root->left, item)) {
if( root->balance-- < 0) {
avl_swr(root); //Rotate the node right.
print_avl(root); //Here, the tree is corrupted.
return 0;
}
return 1;
}
}
} else {
if(!root->right) {
root->right = get_new_node(item);
if(++(root->balance)) return 1;
return 0;
}
else {
if(avl_insert(root->right, item)) {
root->balance++;
return 1;
}
}
}
return 0;
}
void avl_swr(Node* root)
{
Node *node = root;
root = node->left;
node->left = NULL;
node->balance = 0;
root->right = node;
root->balance++;
print_avl(root); // It is working fine here.
}
Node * get_new_node (char *item) {
Node * node = (Node *)malloc(sizeof(Node));
node->item = item;
node->left = NULL;
node->right = NULL;
node->balance = 0;
return node;
}
void print_avl (Node *node)
{
_print_avl(node, 0, "\t\t");
}
void _print_avl (Node *node, int depth, const char *delim)
{
if(!node)
return;
int i = 0;
while(i++ < depth) printf("%s", delim);
printf("--> %s:%d\n", node->item, node->balance);
depth++;
if(node->left)
_print_avl (node->left, depth, delim);
if(node->right)
_print_avl (node->right, depth, delim);
}
The problem is when I rotate the tree, using avl_swr (), it is successfully rotated according to the print_avl (), but when the function returns to the caller, the tree is corrupted. Any ideas?
The problem with avl_swr() is related to the function signature: void avl_swr(Node* root) and the assignment: root = node->left;
The root pointer is not being updated when the function returns (only a local copy within the function is being updated). The signature should be: void avl_swr(Node** root) in order to have the desired result.
The copy of the pointer is updated. You need to pass in a pointer to a pointer in your rotate function.
That's because the root variable in avl_insert does not change in avl_swr. When you pass it to avl_swr, a copy of the pointer is made. You change this pointer.
Change the calls to root = avl_swr(...) and have avl_swr return the root.
not 100% sure, but I do see one problem. In avl_swr() you change root to left subtree. So when you print out in avl_swr() you'll have root = "thur2". But when you return to avl_insert(), root there is unchanged, still pointing to "thura", which now has no children. So when you print that root it shows no children. Perhaps that's what you mean by corrupted?
The solution is obviously to change the "root" in avl_insert(). You can do this by having avl_swr return the new root value, or by changing the parameter from "Node* root" to "Node** root" so that change in avl_swr is "passed back" to avl_insert

Resources