passing an uninitialized variable throwing an error using C - c

I have this code :
typedef struct node
{
int data;
struct node *left;
struct node *right;
} node;
void Build (node *root , int i)
{
if (i < 7)
{
root = (node *)malloc (sizeof(node));
root->data = i;
Build(root->left,2*i+1);
Build(root->right,2*i+2);
}
else
root = NULL;
}
void Print (node *root)
{
if (root)
{
printf ("%d ",root->data);
Print(root->left);
Print(root->right);
}
}
void main()
{
node *tree;
Build(tree,0);
Print(tree);
}
two things that I dont understand ,
1. why can't I pass Build(tree,0) ? it says it's uninitialized , but why shuold I care if it's uninitialized ? I'm allocating all the memory needed straight away so it's gonna be pointing on the new allocated node.
how can I fix this code? thank you!!!

Your node * to tree is uninitialized.
node *tree;
That matters because the code line
root = (node *)malloc (sizeof(node));
allocates memory to a local copy of root. Once you leave function scope of Build, the copy of root goes out of scope. Memory leak.
Remember, everything is passed by value in C.
If you really want Build to allocate the memory, the signature would have to be
void Build (node **root , int i)
and your code in that method would have to refer to *root instead of root.

Parameters are passed by value - the location in memory is not actually passed. So when you call Build, you're just passing in the value of tree, which happens to be uninitialized. The Build function creates a local root variable with that value - when you set root = ... in Build, you're over-writing that undefined value with the new value, but that new value is still just in the local root variable - it is never seen by the tree variable in main.
What you really want to do is have Build return the newly created tree pointer:
node * Build(int i)
{
node *root;
...
root->left = Build(2*i+1)
...
return root;
}
void main()
{
...
tree = Build(0);
...
}

Related

pointers - inconsistent access to memory location

I am trying to define a simple linked list
#include <stdio.h>
struct node{
int value;
struct node* next;
};
typedef struct {
struct node* root;
} ll;
void add_to_ll(int value, ll* linked_list) {
struct node new_node = {value, linked_list->root};
linked_list->root = &new_node;
}
void print_ll(ll* ll2) {
printf("%p", ll2);
struct node* temp = ll2->root;
while (temp->next != NULL) {
printf("%d ", temp->value);
temp = temp->next;
}
}
int main()
{
printf("Creating a linked list...\n");
struct node root_node = {1, NULL};
ll my_linked_list = { &root_node };
for (int i = 0; i < 10000; i++) {
add_to_ll(i, &my_linked_list);
}
printf("my_linked_list root value %d\n", my_linked_list.root->value);
printf("my_linked_list root value %d\n", my_linked_list.root->value);
printf("my_linked_list root value %d\n", my_linked_list.root->value);
return 0;
}
The output I am getting is:
Creating a linked list...
my_linked_list root value 9999
my_linked_list root value 429391991
my_linked_list root value 429391991
I am able to get the value of the root node correctly the first time. But on trying to read it the second time (and thereafter) the value changes. What am I missing?
Your problem is with the memory allocation strategy in add.
void add_to_ll(int value, ll* linked_list) {
struct node new_node = {value, linked_list->root};
linked_list->root = &new_node;
}
Here you're instatiating new_node as a local variable. Non-static local variables have a lifespan equal to that of their block. After you exit the block, that memory (which is actually the stack) is available for successive allocations that will overwrite your object. Use explicit allocation, that means malloc, to have objects whose lifespan is independent from the scope of allocation.
I would also point out the naming... The most explicit name should be that of the type, not the variable. So struct linked_list ll and not the other way around.
This function:
void add_to_ll(int value, ll* linked_list) {
struct node new_node = {value, linked_list->root};
linked_list->root = &new_node;
}
Constructs a node on the stack and adds it to the list.
When you return from this function the stack is popped and the list root points to unallocated memory on the stack that will later be reused.

Not able to free memory from function

I have a C program that implements trees. my cleanup function looks like this:
void cleanup_tree( TreeNode* root ){
printf("Called\n");
if(root->left!=NULL){
cleanup_tree(root->left);
}
if(root->right!= NULL){
cleanup_tree(root->right);
}
if(root->right==NULL &&root->left==NULL) {
/*free(root);*/
free(root->word);
free(root);
root = NULL;
}
}
My Tree struct has
typedef struct TreeNode_st {
char *word; // the word held in this node
unsigned int frequency; // how many times it has been seen
struct TreeNode_st *left; // node's left child
struct TreeNode_st *right; // node's right child
} TreeNode;
I am initialising a tree like this :
TreeNode* initTreeNode(){
TreeNode *mainNode= (TreeNode*)malloc(sizeof(TreeNode));
mainNode->frequency = 0 ;
mainNode->word = NULL;
mainNode->left = NULL;
mainNode->right = NULL;
return mainNode;
}
in my main, I have called
TreeNode *mainNode =initTreeNode();
and I'm doing operations on it , and just before program exit, i called
cleanup_tree(mainNode);
Valgrind reported memory leaks, so just to test , i did
I put
printf("~~~FINAL NULL TEST %s",mainNode->left->right->word);
below my cleanup_tree line,
And i'm able to see the word even now.
What am I doing wrong ?
There are two ways:
You pass it a pointer-to-a-pointer: void cleanup_tree( TreeNode **root)
You set the fields to NULL after the cleanup returns:
Currently, the changes made by the function are not reflected in the node parameter you passed.
Ad 2:
cleanup_tree(root->right);
root->right= NULL;
You seem to be under the impression that setting root = NULL at the end of this function will be visible in the calling function so that the third if block gets called. That's not the case.
You want to always free() the word as well as the node itself.
void cleanup_tree( TreeNode* root ){
printf("Called\n");
if(root->left!=NULL){
cleanup_tree(root->left);
}
if(root->right!= NULL){
cleanup_tree(root->right);
}
free(root->word);
free(root);
}

Why the value of root is printed as 0 in main function?

#include <stdio.h>
#include <stdlib.h>
struct nodeTree {
int data;
struct nodeTree* left;
struct nodeTree* right;
};
struct nodeTree* insertRoot(struct nodeTree** root, int data) {
if(!(*root)) {
struct nodeTree *temp = malloc(sizeof(struct nodeTree));
if(!temp) {
exit(-1);
}
temp->data = data;
temp->left = 0;
temp->right = 0;
(*root) = temp;
free(temp);
return *root;
}
}
int main() {
struct nodeTree *root = NULL;
root = insertRoot(&root,10);
printf("%d\n",root->data);
return 0;
}
I wrote a function to insert a value in the root of a binary tree. In my insert function I assign a temp node and after inserting the value into the temp node I assign the temp node to root and free the temp node. I understand I can directly malloc into the root variable and assign the data to it. What happens when free(temp) is called and how does it affect the root variable ?
You should not free() temp, because you still point to it with root, they point to the same data, hence freeing temp does free *root too.
As to why it's printing 0 it's just a coincidence, because having free()ed root in the function where you allocated it, and accessing it in main() invokes undefined behavior, a consequence might be that printf() prints, 0, which is a behavior, and since it's undefined, any other behavior is actually possible.

BST program in C

Please help me with this. I keep getting seg faults!
I want to use recursion to create and insert a new node.
Please help me debug this.
//Create a Binary Search Tree From an array.
struct Tree
{
int data;
struct Tree *lchild;
struct Tree *rchild;
};
struct Tree *root = NULL;
struct Tree *node(int val)
{
struct Tree *tempnode;
tempnode = (struct Tree*)malloc(sizeof(struct Tree));
tempnode->data = val;
tempnode->rchild = NULL;
tempnode->lchild = NULL;
return tempnode;
}
void createTree(struct Tree *curr, int val)
{
struct Tree *newnode = node(val);
if (curr == NULL)
curr = newnode;
else if(val < curr->data)
{
createTree(curr->lchild,val);
}
else if(val > curr->data)
{
createTree(curr->rchild,val);
}
else
printf("Error Similar data found\n");
}
void inorder(struct Tree *root)
{
if (root->lchild != NULL)
inorder(root->lchild);
printf("[%d] ",root->data);
if (root->rchild != NULL)
inorder(root->rchild);
}
int main()
{
// root = NULL;
int i = 0, arr[5] = {41,12,32,23,17};
for(i;i<5;i++)
createTree(root,arr[i]);
inorder(root);
return 0;
}
why do I keep getting seg fault. Can someone explain me?
Am I doing something I should not? Or am I missing at some point?
Learn to use a debugger!
Stepping through the main function, you would have seen that the value of root would have remained NULL after each call to createTree
The createTree function is not modifying the value of root, but only modifying its copy of the value of root.
Your createTree function needs to take a struct Tree **curr, a pointer-to-a-pointer. This allows the function to modify the original value, not the local copy.
The root of the tree is not assigned anywhere; in your function createTree you probably think that it is assigned in:
if (curr == NULL)
curr = newnode;
But curr is local to the function and does not affect root. You need to change the argument curr to be a pointer to pointer, otherwise the function does not work for assigning the root node, or child nodes. The root of the tree is not assigned anywhere; in your function createTree you probably think that it is assigned in:
if (curr == NULL)
curr = newnode;
But curr is local to the function and does not affect root even if you gave it as the argument curr. You need to change the argument curr to be a pointer to pointer, otherwise the function does not work for assigning the root node, or child nodes. That is, the function declaration becomes:
void createTree(struct Tree **curr, int val)
Of course you must then change the use of curr inside the function accordingly (i.e., the address pointed to is *curr where it used to be curr), calls of the function need to pass the address, and not value, of the pointer (e.g., createTree(&root, arr[i])).
edit: Or, indeed, have the function return curr and always assign the return value to the relevant pointer at every place where you call createTree, thanks to #JonathanLeffler for the observation.

Linked list loops endlessly

I'm writing a simple linked list implementation for the sake of learning. My linked list consists of node structures that contain an int value and a pointer to the next node. When I run my code, it loops endlessly even though it should terminate when it reaches a NULL pointer. What am I doing wrong?
#include <stdio.h>
struct node {
int value;
struct node *next_node;
};
struct node * add_node(struct node *parent, int value)
{
struct node child;
child.value = value;
child.next_node = NULL;
parent->next_node = &child;
return parent->next_node;
}
void print_all(struct node *root)
{
struct node *current = root;
while (current != NULL) {
printf("%d\n", current->value);
sleep(1);
current = current->next_node;
}
}
int main()
{
struct node root;
root.value = 3;
struct node *one;
one = add_node(&root, 5);
print_all(&root);
}
Your program exhibits undefined behavior: you are setting a pointer to a locally allocated struct here:
struct node child;
child.value = value;
child.next_node = NULL;
parent->next_node = &child;
return parent->next_node;
Since child is on the stack, returning a parent pointing to it leads to undefined behavior.
You need to allocate child dynamically to make it work:
struct node *pchild = malloc(sizeof(struct node));
// In production code you check malloc result here...
pchild->value = value;
pchild->next_node = NULL;
parent->next_node = pchild;
return parent->next_node;
Now that you have dynamically allocated memory, do not forget to call free on each of the dynamically allocated nodes of your linked list to prevent memory leaks.
add_node returns a pointer to a local variable which immediately goes out of scope and may be reused by other functions. Attempting to access this in print_all results in undefined behaviour. In your case, it appears the address is reused by the current pointer, leaving root->next_node pointing to root.
To fix this, you should allocate memory for the new node in add_node
struct node * add_node(struct node *parent, int value)
{
struct node* child = malloc(sizeof(*child));
if (child == NULL) {
return NULL;
}
child->value = value;
child->next_node = NULL;
parent->next_node = child;
return child;
}
Since this allocates memory dynamically, you'll need to call free later. Remember not to try to free root unless you change it to be allocated using malloc too.

Resources