C segmentation fault in insert to binary tree - c

I am still very new to C, and am trying to figure out why I (believe) that I am getting a segmentation fault. I say believe, because the exe stops working, and so I just try and run it in Eclipse's debugger, and that's where I see the error happening. Any help/suggestions/criticisms are highly welcomed.
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
struct node *left;
struct node *right;
double key;
} node;
void addNode(double value, node **node);
double dRand();
//node* search(double value, node *root);
void killTree(node *root);
int main(void)
{
int nodesToAdd, i;
node *n = NULL;
node **p = &n;
nodesToAdd = 10;
for(i=0;i<nodesToAdd;i++)
{
printf("DEBUG: Adding node %d to tree\n", i+1);
addNode(dRand(), p);
}
printf("DEBUG: Finished creating tree\n");
printf("DEBUG: Freeing memory of tree\n");
killTree(n);
return 0;
}
double dRand()
{
return ((double)rand()/RAND_MAX)*10;
}
void addNode(double value, node **tree)
{
node *insert = malloc(sizeof(*insert));
insert->key = value;
while(*tree){
if(value < (*tree)->key) tree = &(*tree)->left;
else if(value > (*tree)->key) tree = &(*tree)->right;
else return;
}
*tree = insert;
}
void killTree(node *node)
{
if(!node){}
else
{
killTree(node->left);
killTree(node->right);
printf("DEBUG: Deleting pointer to node of value %f from mem\n", node->key);
free(node);
}
}
EDIT: I think that the error comes from trying to reference the right and left nodes before they are allocated memory, but I'm not sure what it is that I am doing wrong.
EDIT2:Thanks so much, that worked wonderfully!

You have a memory leak in your addNode function if a match is found. You allocate, then search. You should search, then allocate only if the search failed.
Regarding your crash, you're not initializing a new node's left and right pointers to NULL. This is critical. The next time you enter the tree to chase down a search, you will dereference indeterminate pointers, and invoke undefined behavior as a result.
Perhaps something like this:
void addNode(double value, node **tree)
{
// search first
while (*tree)
{
if (value < (*tree)->key)
tree = &(*tree)->left;
else if((*tree)->key < value)
tree = &(*tree)->right;
else return;
}
// no match, so add
*tree = malloc(sizeof(**tree));
(*tree)->key = value;
(*tree)->left = (*tree)->right = NULL; // note: set to null
}
Next, though not critical, your main() function has no need for p. You can use your node pointer by-address directly:
int main(void)
{
int nodesToAdd, i;
node *n = NULL;
nodesToAdd = 10;
for(i=0;i<nodesToAdd;i++)
{
printf("DEBUG: Adding node %d to tree\n", i+1);
addNode(dRand(), &n);
}
printf("DEBUG: Finished creating tree\n");
printf("DEBUG: Freeing memory of tree\n");
killTree(n);
return 0;
}
And for what it's worth, if your new to C, this isn't terrible. Grasping double-indirection is a common stall-point in the C learning curve, and your use in your add function wasn't terrible at all. Keep at it.

Related

Binary Search Tree in C causing a Heap Corruption Error

So I'm a Python programmer and I'm trying to teach myself C. Just as practice, I've been trying to implement a simple Binary Search Tree in C. I've never had to work with memory allocation or pointers before and its been causing a lot of errors.
My program has been giving me exit code -1073740940 (0xC0000374) which I understand means that the heap has been corrupted. It's a bit of a long program, so I just included the offending function.
This insert function is repeatedly called using a for loop to insert the contents of an array into the binary search tree. The array's contents are 5, 4, 6, 3, 7, 2, 8, 1, 9, and 0 (designed to make the tree balanced).
So the function first has 5 passed to it. The pointer called by pBST->listRoot is NULL (pBST is a pointer to a list struct), so insert 5 as a the root node. This works fine. Then 4 is passed to the function. Since there is already a root, it checks the children of that root. 4 is less than 5 so check 5's left child. The pointer for 5's left child is null, so it attempts to insert 4 as a new node. This is the line that crashes the program:
struct Node* pTemp = calloc(1, sizeof(struct Node));
I've tried a couple variations of this line. Here's the kicker: cLion's debugger cannot reproduce this. When I run it through the debugger, it works perfectly. I think it has to do with the fact that the debugger uses the same memory addresses every time for reproducibility. I left the debugging printf statements and added the code for the Node and binarySearchTree structs.
typedef struct Node BSTNode;
struct Node {
BSTNode* parent;
BSTNode* left;
BSTNode* right;
int* data;
};
typedef struct {
BSTNode* listRoot;
int nodeCount;
} binarySearchTree;
void insert(int Value, binarySearchTree* pBST) {
/*
* This function
*/
//====DEBUG CODE============
int debugIterations = 0;
printf("Now inserting %d \n", Value);
//=====END DEBUG CODE=======
//if no root, make it the root
if (pBST->listRoot == NULL) {
struct Node* newNode = calloc(1, sizeof(binarySearchTree));
(*pBST).listRoot = newNode;
(*pBST).listRoot->data;
(*pBST).listRoot->data = Value;
//pBST->listRoot->data = Value;
pBST->listRoot->parent = NULL;
pBST->listRoot->right = NULL;
pBST->listRoot->left = NULL;
return;
} else {
struct Node* pCursor = pBST->listRoot;
while (1){
printf("Iterations: %d \n", debugIterations);
debugIterations++;
//Check if the number is the same
if (pCursor->data == Value){
printf("ERROR: Tried to insert duplicate value into tree");
return;
}
//Is the value > the node?
else if (pCursor->data < Value) {
//DEBUG
printf("== check succeeded, now value > data\n");
// Is the value a Null?
if (pCursor->right == NULL) {
//DEBUG
printf("Running function to insert %d as a new node to the right\n", Value);
//If yes, then insert the value as a nul
//Create Node
struct Node* pTemp = calloc(1, sizeof(binarySearchTree));
pTemp->data = Value;
pTemp->parent = pCursor;
pCursor->right = pTemp;
pTemp->left = NULL;
pTemp->right = NULL;
return;
}
//If no, then iteravely continue.
else {
printf("Iteravely continuing to the right");
pCursor = pCursor->right;
continue;
}
}
//Is the value < the root?
else {
//DEBUG
printf("== check succeeded, now value < data\n");
//Is the value a Null?
if (pCursor->left == NULL) {
//DEBUG
printf("Running function to insert %d as a new node to the left\n", Value);
//If yes, then insert the value where the null is.
//Create Node
struct Node* pTemp = (struct Node*)calloc(1, sizeof(struct Node));
printf("Successfully declared and allocated memory");
pTemp->data = Value;
pTemp->parent = pCursor;
pCursor->left = pTemp;
pTemp->left = NULL;
pTemp->right = NULL;
return;
}
//If no, then iteravely continue
else{
printf("Iteravely continuing to the right");
pCursor = pCursor->left;
continue;
}
}
}
}
}
The line
struct Node* pTemp = calloc(1, sizeof(binarySearchTree));
is wrong. The structure binarySearchTree has one pointer and one int, but the structure struct Node has 4 pointers, so struct Node should be larger than binarySearchTree and this allocation will allocate less space than required, leading to out-of-range access.
It should be:
struct Node* pTemp = calloc(1, sizeof(*pTemp));
or
struct Node* pTemp = calloc(1, sizeof(struct Node));
Also it looks very weird to store the data int Value in the member int* data; with (*pBST).listRoot->data = Value;. It looks like the member should be int, not int*.

Problem deleting the only node from a linked list

I am trying to create a function to delete a certain node if its value matches the value entered by the user. I created a case if there is only a single node, but after deleting the node with free(curr_node) and calling traverse function, the cmd prints out numbers endlessly. What am I missing?
typedef struct Node {
int data;
struct Node *next;
}Node;
Node *head = NULL;
int node_number = 0;
void traverse(Node *head, int count) {
int i = 1;
if(head == NULL) {
printf("No nodes to traverse!");
return;
}
printf("%d node(s), with their respective value: \n", count);
while(head != NULL) {
if(i == count)
printf("%d\n", head->data);
else
printf("%d-", head->data);
head = head->next;
i++;
}
}
void delete_item(Node *head) {
Node *curr_node = head;
int value;
printf("Enter value to search by: ");
scanf("%d", &value);
while(curr_node != NULL) {
if(curr_node->data == value) {
if(curr_node->next == NULL) {
free(curr_node);
head = NULL;
printf("Node deleted successfully!\n");
return;
}
}
//curr_node = curr_node->next;
}
}
Node *create_item() {
Node *result = NULL;
result = (Node *)malloc(sizeof(Node));
if(result == NULL) {
printf("Couldn't allocate memory!");
return 0;
}
printf("Value of node %d: ", node_number + 1);
scanf("%d", &result->data);
result->next = NULL;
node_number++;
return result;
}
int main() {
int nodes;
Node *temp;
head = create_item();
delete_item(head);
traverse(head, node_number);
return 0;
The change to head is not captured by the caller. The fact is, head is actually a local variable to delete_node, and any changes to it (not to be confused with changed through it using deference operations), are not being captured by the caller.
All function arguments in C are by-value. Some will say "that's not true for arrays"; they're wrong. Used in an expression, the "value" of an array is defined by the language standard as a temporary pointer referring to the address of the first element. I.e. still by-value, its just the value isn't what you may expect. But in your case, head is by value. If you had a function void foo(int x) you already know that modifying x within foo does not change the caller's int they passed; the same is true here. Just because its a pointer makes no difference. If you want to modify a caller-argument you have to build the road to get there.
There are two general schools around this.
Use a pointer to pointer argument and pass the address of head in main. This requires deference of the pointer-to-pointer to get the actual list head, but also allows you to modify the callers pointer.
Use the return result of the function to communicate the current list head back to the caller (i.e. the head after whatever operation is being performed.
The first is more complicated, but allows you to use the return result for other purposes (like error checking, hint). The latter is easier to implement. Both will accomplish what you want. The former is shown below:
void delete_item(Node **head)
{
int value;
printf("Enter value to search by: ");
if (scanf("%d", &value) == 1)
{
while (*head)
{
if ((*head)->data == value)
{
void *tmp = *head;
*head = (*head)->next;
free(tmp);
printf("Node deleted successfully!\n");
break;
}
head = &(*head)->next;
}
}
}
The caller, main in this case, needs to be modified as well:
delete_item(&head); // <== note passed by address now.

My code for pre-order traversal of Binary Search Tree is working but how is the stack whose each element is a pointer to the structure working?

This is my code of preorder traversal of BST. It's working fine on Ubuntu. But I don't understand one thing.
In the function iterative_preorder(), I actually wanted a stack to store the pointers to the structure that I defined on the top. I want to know the concept that how is it working. Since, while allocating memory to the stack, I didn't specify anywhere separately that stack should contain size number of pointers to the structure.
Like, when we define:
int stack[size];
We know that stack[1] will be the second block in the stack. But here, I used malloc, which actually just makes one block of the size specified as size * sizeof(node *).
So when the program executes:
stack[++top] = root;
How does the program understand that it has to go to the next pointer to the structure in the stack? I hope my question is clear.
I made another small program, based on the confusion that I had. Here, instead of structure, I used int. I tried to create a stack of size 2, which stores pointers to the integer. Here's the code:
#include <stdio.h>
#include <stdlib.h>
void main() {
int** stack = (int**)malloc(2 * sizeof(int*));
printf("%d", *stack[0]);
}
But this code is throwing segmentation fault (core dumped). As both the codes used the same logic, just that this one used int instead of structure, I don't understand why this is throwing error.
#include <stdio.h>
#include <stdlib.h>
int size = 0;
typedef struct mylist {
int data;
struct mylist *left;
struct mylist *right;
} node;
node *root;
void create_root(node *root) {
root = NULL;
}
//Inserting nodes
node *insert(node *root, int val) {
node *ptr, *parentptr, *nodeptr;
ptr = (node*)malloc(sizeof(node));
ptr->data = val;
ptr->left = NULL;
ptr->right = NULL;
if (root == NULL)
root = ptr;
else {
parentptr = NULL;
nodeptr = root;
while (nodeptr != NULL) {
parentptr = nodeptr;
if (val < nodeptr->data)
nodeptr = nodeptr->left;
else
nodeptr = nodeptr->right;
}
if (val < parentptr->data)
parentptr->left = ptr;
else
parentptr->right = ptr;
}
return root;
}
void iterative_preorder(node *root) {
if (root != NULL) {
int top = -1;
node **stack = (node**)malloc(size * sizeof(node*));
node *cur;
stack[++top] = root;
while (top > -1) {
cur = stack[top--];
printf("%d\t", cur->data);
if (cur->right != NULL)
stack[++top] = cur->right;
if (cur->left != NULL)
stack[++top] = cur->left;
}
}
}
void main() {
int option, val;
node *ptr;
int flag = 1;
create_root(root);
while (flag != 2) {
printf("\nChoose-\n1-Insert\n2-Iterative Preorder Traversal\n3-Exit\n");
scanf("%d", &option);
switch (option) {
case 1: {
printf("\nEnter the value of new node\n");
size++;
scanf("%d", &val);
root = insert(root, val);
}
break;
case 2:
iterative_preorder(root);
break;
case 3:
flag = 2;
break;
default:
printf("\nWrong entry\n");
}
}
}
Your code has a dereference of uninitialized pointer error.
int** stack = (int**)malloc(2*sizeof(int*));
printf("%d",*stack[0]);
In the above code, stack points to an array of two int pointers, what stack[0] points to? it's not initialized.
A live test of your code is available here segfault. you can modify and test it again.

Using a Binary Tree

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct node_{
int val;
struct node_ *left;
struct node_ *right;
}node;
node* insert(node* root,int val);
void inorder(node* root);
int main(void)
{
int i;
int item;
node* root = NULL;
srand(time(NULL));
for( i = 0; i < 10; i++)
{
item = rand()%15;
insert(root,item);
}
inorder(root);
return 0;
}
node* insert(node* root,int val)
{
if(root == NULL)
{
root = malloc(sizeof(node));
if(root!= NULL)
{
(root)->val = val;
(root)->left = NULL;
(root)->right = NULL;
}
else
printf("%d not inserted. No memory available.\n",val);
}
else
{
if(val < (root)->val)
{
insert((root->left),val);
}
if(val>root->val)
{
insert(((root)->right),val);
}
}
}
void inorder(node* root)
{
printf("%p",root);
if(root != NULL)
{
inorder(root->left);
printf("%3d",root->val);
inorder(root->right);
}
}
I am trying to create a binary tree and print out the values in order. However when I run this code the printf of the address prints out nil obviously meaning that my tree is empty so the printf and recursion below does not run. I cannot figure out where I went wrong, any suggestions or answers would be appreciated because I can't figure out why the root would be null after calling all of those inserts in main.
You pass root as a parameter to insert() (which says it is going to return something but doesn't). Inside insert you malloc your node and assign it to the local variable root. Nothing you ever do makes it out of the insert function.
Try returning something from insert, or using a global root.
As #JoshuaByer hints in the comments below, another approach is to make your insert method "pass by reference" so it can effectively modify what was passed to it.
void insert(node** rootp,int val)
{
if(*rootp == NULL)
{
*rootp = malloc(sizeof(node));
}
/* and so on */
If you don't understand what this is saying, google "Pass by reference in C" and I'm positive you'll get some good information.
In main() after declaring and initializing root (node* root = NULL;) you're never assigning it. In order to fix you should probably change the lin insert(root,item); to root = insert(root,item);.
Also note that although insert is defined as returning node * it does not return any value.

Binary Search Tree Issues

I'm working on a binary tree with a list tacked on to the data, yet I can't tell if the list is being populated or not. The code runs alright but when I try to call to print out the tree I get a freeze in my code. I believe everything is being pointed to properly but it's obvious there is a flaw in the logic somewhere.
struct declarations
typedef struct lineList
{
int lineNum;
LIST *next;
}LIST;
typedef struct nodeTag{
char data[80];
LIST *lines;
struct nodeTag *left;
struct nodeTag *right;
} NODE;
declaration and pass to function from main
NODE *root = NULL;
readFromFile(argv[1], root);
readfromfile(working function) then calls insertword
insertWord(root, keyword, lineNum);
insertWord, addToList functions(problem area)
NODE *allocateNode(char *data, int line)
{
NODE *root;
LIST *newNum;
if(!(root = (NODE *) malloc (sizeof(NODE))))
printf( "Fatal malloc error!\n" ), exit(1);
strcpy(root->data, data); //copy word
(root)->left = (root)->right = root->lines = NULL; //initialize
if (!(newNum =(LIST *) malloc (sizeof(LIST))))
printf( "Fatal malloc error!\n" ), exit(1);
newNum->lineNum = line;
root->lines = newNum;
return root;
}
/****************************************************************
ITERATIVE Insert
*/
NODE *insertWord(NODE *root, char *data, int line)
{
NODE *ptr_root = root;
printf("inserting %s\n", data);
if(root == NULL)
{
root = allocateNode(data, line);
return root;
}
while(ptr_root)
{
if (strcmp(data, ptr_root->data > 0))
{
if(ptr_root->right)
ptr_root = ptr_root->right; //traverse right
else
ptr_root->right = allocateNode(data, line);
}
else if (strcmp(data, ptr_root->data) < 0)
{
if(ptr_root->left) //traverse left
ptr_root = ptr_root->left;
else
ptr_root->left = allocateNode(data, line);
}
else
{
printf("Node already in the tree!\n");
addToList(ptr_root, line);
}
}
printf("5\n");
return root;
}
void printTreeInorder(NODE *root)//simple print, freeze on call to function
{
if(root)
{
printTreeInorder(root->left);
printf( "%s\n", root->data );
printTreeInorder(root->right);
}
return;
}
Let's look at insertWord():
At the end of your while loop, we know that ptr_root == NULL.
We then allocate memory for ptr_root.
We then initialize the contents of ptr_root.
We then perform a memory leak on ptr_root.
Note that you need to retain the parent of the new node, and you need to point the its left or right pointer to this new node.
It also sounds like you understand how to use a debugger. If that's true, you should be able to see that root doesn't change between calls to insertWord().
In the code that you've posted with an attempted fix, you're missing one key thing. Let's look at a function:
void foo(NODE *root) {
printf("before malloc: %p\n", root);
root = malloc(sizeof(NODE));
printf("after malloc: %p\n", root);
}
int main() {
NODE *root = NULL;
printf("before function: %p\n", root);
foo(root);
printf("after function: %p\n", root);
}
This code will produce:
before function: 0x0
before malloc: 0x0
after malloc: 0x123ab129
after function: 0x0
Note that any changes to the value of root is not propagated out of the function. Things that you change to *root would though.

Resources