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.
Related
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.
I've tried applying advice from other threads regarding the EXC_BAD_ACCESS message, but with no success. The note appears next to Node Create_Child (Node Parent_Node, int item) {.
typedef struct {
int Win_Loss;
int parent;
int identifier;
int Object_Moved;
int Wolf;
int Goat;
int Salad;
int Boat;
} Node;
Node Create_Child (Node Parent_Node, int item) {
Node Child;
Child.Boat = (-1)*Parent_Node.Boat;
Child.Wolf = Parent_Node.Wolf;
Child.Goat = Parent_Node.Wolf;
Child.Salad = Parent_Node.Salad;
int* Child_Items[] = {&Child.Wolf, &Child.Goat, &Child.Salad, &Child.Boat};
Child.parent = Parent_Node.identifier;
Child_Items[item][0] *= (-1);
Child.Object_Moved = item;
return Child;
}
Any insight? Memory allocation doesn't seem to be the issue, but I'm probably not seeing something.
The pointers e.g. Child.Wolf are local to the function, they have no meaning outside your Create_Child function yet you assign those addresses to Child.Object_Moved and return a copy of it.
You should allocate Child on the heap instead
Node* Create_Child(Node Parent_Node, int item) {
Node* Child = malloc(sizeof(Node));
Child->Boat = -1*Parent_Node.Boat;
...
int* Child_Items[] = { &Child->Wolf, .. };
Also it is good to sanity check all arguments to your function
before using them. e.g. item in range?, Parent_Node valid info?
I cannot figure out how to run this correctly, gives segmentation error. A piece of code is below. Can you look at head too , i am not sure if it is right way of initialising head to null in another file , it is run as follows :
Table tb ;
tb= initialise_table (table_size);
tb = insert(text_words,tb);
//these 3 typedef declarations are in a "some.h" file
typedef struct node * tree_ptr;
typedef char* Key_Type;
typedef struct table* Table;
struct node {
Key_Type element;
tree_ptr left;
tree_ptr right;
};
struct table {
tree_ptr head;
};
Table init_table() {
Table head = NULL;
}
Table insert(Key_Type key ,Table temp ) {
tree_ptr t = (tree_ptr)malloc(sizeof(tree_ptr));
t->element = key;
// t->left = t->right = NULL;
if (temp->head==NULL) {
temp = (Table)malloc (sizeof (Table));
temp->head = t;
printf("empty tree ");
}
else {
temp = insert(t->element,temp);
printf("inserted into ");
}
return temp;
printf("wowo!");
}
The primary issue is in the code which, you say, is used to invoke the functions:
Table tb;
tb = insert(text_words, tb);
You have an uninitialized pointer, tb, which you pass to the function. Inside the function, you have:
Table insert(Key_Type key, Table temp)
{
tree_ptr t = (tree_ptr)malloc(sizeof(*t)); // Fixed size
t->element = key;
// t->left = t->right = NULL;
if (temp->head==NULL)
{
You're therefore accessing (dereferencing) the undefined pointer, and your program is crashing.
You should, I assume, be initializing your table with table_init(), but that function is actually no help whatsoever. It defines and initializes a local variable, but doesn't return anything even though it promises to do so.
Please see Is it a good idea to typedef pointers? The short answer is 'No, it usually isn't a good idea'.
You still have problems even if you fix the calling code like this (a necessary but not sufficient step):
Table tb = NULL;
tb = insert(text_words, tb);
or maybe:
Table tb = init_table();
tb = insert(text_words, tb);
but you need a seriously upgraded version of init_table(), such as:
Table init_table(void)
{
Table root = malloc(sizeof(*head));
root->head = NULL;
return root;
}
Your code in insert() needs to ensure that it does not dereference a null pointer (instead of an indeterminate pointer).
Table insert(Key_Type key, Table root)
{
tree_ptr t = (tree_ptr)malloc(sizeof(*t)); // Fixed size
t->element = key;
t->left = t->right = NULL;
if (root == NULL)
{
root = init_table();
root->head = t;
}
else
{
…
}
return root;
}
Given the Key_Type is a char * in disguise, you may need to review how you save the keys in the tree structure; you may need to use strdup() to copy the data. It is impossible to say for sure without seeing how you are managing the strings that you pass to the insert() function. It could be OK to just save the pointer if the calling code ensures that a new pointer is passed each time. OTOH, if the same pointer is passed each time, you definitely need to copy the data, and using strdup() is a sensible way of doing that. Note that strdup() is standard on POSIX; it is not part of standard C.
Here's one major problem:
tree_ptr t = (tree_ptr) malloc(sizeof(tree_ptr));
should be:
tree_ptr t = (tree_ptr) malloc(sizeof(struct node));
Your code doesn't actually do any binary search. Indeed, it just infinitely recurses creating new nodes. Try something more like this:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct Node
{
char *element;
struct Node *left;
struct Node *right;
} Node;
typedef struct
{
Node *root;
size_t size;
} Tree;
void Tree_init(Tree *t);
Node *Tree_insert(Tree *t, const char *key);
void Tree_insert_r(Node *subtree, Node *n, size_t size);
void Tree_pre_order_r(Node *subtree);
void Tree_init(Tree *t)
{
t->root = NULL;
t->size = 0;
}
Node *Tree_insert(Tree *t, const char *key)
{
Node *ret = (Node*) malloc(sizeof(Node));
if (ret)
{
ret->left = ret->right = NULL;
if ((ret->element = strdup(key))) /* make a copy of key */
{
if (NULL != t->root)
Tree_insert_r(t->root, ret, t->size);
else
t->root = ret;
++t->size;
}
else
{
free(ret);
ret = NULL;
}
}
return ret;
}
void Tree_insert_r(Node *subtree, Node *n, size_t size)
{
int cmp = strcmp(n->element, subtree->element);
if (cmp < 0 || (cmp == 0 && size % 2 == 0))
{
if (NULL != subtree->left)
subtree = subtree->left;
else
{
subtree->left = n;
return;
}
}
else
{
if (NULL != subtree->right)
subtree = subtree->right;
else
{
subtree->right = n;
return;
}
}
Tree_insert_r(subtree, n, size);
}
void Tree_pre_order_r(Node *subtree)
{
if (NULL == subtree)
return;
fprintf(stdout, "'%s'\n", subtree->element);
Tree_pre_order_r(subtree->left);
Tree_pre_order_r(subtree->right);
}
int main()
{
Tree t;
Tree_init(&t);
Tree_insert(&t, "Hello");
Tree_insert(&t, "World!");
Tree_insert(&t, "etc.");
Tree_pre_order(t.root);
return 0;
}
I use nested structure to define the linked-list queue:
queue.h:
#define QUEUE_MAX_SIZE 4096
struct QUEUE_NODE {
char *string;
struct QUEUE_NODE *next;
}queue_node;
struct COMMON_QUEUE {
struct QUEUE_NODE *q_node;
}common_queue;
=================================
queue.c:
/* here I define the operations */
struct COMMON_QUEUE *C_init_queue() {
struct QUEUE_NODE *head;
head = malloc(sizeof(struct QUEUE_NODE));
if (head==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
struct COMMON_QUEUE *new_queue;
new_queue = malloc(sizeof(struct COMMON_QUEUE));
if (new_queue==NULL) {
fprintf(stderr, "Insufficient memory!!!");
return NULL;
}
head->next = NULL;
head->string = NULL;
new_queue->q_node = head;
return new_queue;
}
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
count = 0;
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
return count;
}
int C_enqueue(struct COMMON_QUEUE *q, char *in) {
if (C_get_queue_length(q)>=QUEUE_MAX_SIZE) {
fprintf(stderr, "Linked queue is full!!!");
return ERROR;
}
struct QUEUE_NODE *new_node;
new_node = malloc(sizeof(struct QUEUE_NODE));
if (new_node==NULL) {
return ERROR;
}
new_node->next = NULL;
new_node->string = NULL;
while (q->q_node->next!=NULL) {
q->q_node = q->q_node->next;
}
new_node->next = q->q_node->next;
q->q_node->next = q->q_node;
new_node->string = in;
return OK;
}
but when I use it in the main program, then it jumps into a endless loop, after backtracing, and I knew the problem is at:
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
but it seems correct, but I may make some mistake on my initialization of the two nested struct!
P.S. the I did not list the "free()".
This loop modifies the list while it traverses it. Specifically, it replaces q->q_node with q->q_node->next, which if nothing else will discard your entire loop.
while (q->q_node->next!=NULL) {
count += 1;
q->q_node = q->q_node->next;
}
If you want to correctly traverse the list, you need to declare a separate pointer that you use for traversal. Something like this:
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
struct COMMON_QUEUE *p = q->q_node;
count = 0;
while (p->next != NULL) {
count += 1;
p = p->next;
}
return count;
}
The pointer p will step along the list without modifying the q_node pointers along the way.
You have a similar error in C_enqueue. You really want to use a separate pointer to walk the list, and not assign q->q_node during traversal. You can fix your C_enqueue similarly:
p = q->q_node;
while (p->next != NULL) {
p = p->next;
}
p->next = new_node; /* append the new node after where the list traversal stopped */
new_node->next = NULL; /* always NULL, because you always insert at the end */
One problem with your code is that your iterations through the queue are destructive: rather than using a temporary variable to iterate your linked list, you perform the iteration using the q_node itself. This leads to C_get_queue_length calls effectively destroying the queue, without freeing its nodes (a memory leak).
Here is an example of how to iterate a list non-destructively, using your "get length" method:
int C_get_queue_length(struct COMMON_QUEUE *q) {
int count;
count = 0;
struct QUEUE_NODE node = q->q_node;
while (node->next != NULL) {
count++;
node = node->next;
}
return count;
}
Your decision to pre-allocate one node when creating a queue is also questionable: it appears that the head node is unused, and also excluded from the count. This makes it easier to write the code to insert and delete nodes, but the same could be done with an extra level of indirection (i.e. a pointer to a pointer).
I am having trouble with some code in C accessing the contents of this chain of pointers:
I have these structs:
typedef struct {
unsigned int hash;
char string[10];
void *memory;
} thing;
typedef struct {
int num;
thing *thing;
} node;
typedef struct {
int size;
thing* things;
node* nodes;
} t_system;
Ok. Now I initialize everything like this:
thing* things = NULL;
things = calloc(10, sizeof(thing));
node* nodes = NULL;
nodes = calloc(10, sizeof(node));
t_system* theSystem = NULL;
theSystem = calloc(1, sizeof(t_system));
theSystem->things = things;
theSystem->nodes = nodes;
And now, I want to set this:
theSystem->nodes[2].thing = &theSystem->things[1];
After that line, if I debug and set a breakpoint theSystem nodes points to 0x0
Where am I going wrong?
if (theSystem->nodes[2].thing == NULL) {
theSystem->nodes[2].thing = &theSystem->things[1]; //this is executed
}
if (theSystem->nodes[2].thing == NULL) {
//this is not executed...
}
I can do this:
theSystem->nodes[2].thing->hash = 123;
And debugging shows the correct value for hash, and thing, but not for nodes. it points to 0x0.
You wrote
node* nodes = NULL;
tree = calloc(10, sizeof(node));
You should have written
node* nodes = NULL;
nodes = calloc(10, sizeof(node));
You initialize nodes to NULL on this line:
node* nodes = NULL;
Then you assign nodes to theSystem->nodes on this line:
theSystem->nodes = nodes;
Since you never change the value of nodes in between, theSystem->nodes will also be NULL.
Are you sure the following line is correct:
tree = calloc(10, sizeof(node));
Shouldn't you assign this to nodes instead?