Binary Search Tree Issues - c

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.

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*.

Tree node with arbitrary many child nodes in C

I'm trying to implement a node structure in C that can have arbitrary many child nodes. I wanted to do this idea by using a pointer to a pointer to a struct instead of using an array:
struct Node {
char name[10]; // Name of the node.
int data; // The data it holds.
struct Node *parent; // The parent node.
struct Node **child; //
};
(I don't know if this is the best or even a good but I'm just playing around to learn C better).
I also implemented a print function that prints the members:
void print(struct Node node);
(I know this only prints one node so it wouldn't work for a node with multiple child-nodes).
However, when I try to use this in a main function I get a segmentation fault (core dump):
#include <stdio.h>
#include <stdlib.h>
struct Node {
char name[10]; // Name of the node.
int data; // The data it holds.
struct Node *parent; // The parent node.
struct Node **child; //
};
void print(struct Node node) {
printf("Name: %s\n", node.name);
printf("Data: %d\n", node.data);
printf("Parent: %s\n", (*node.parent).name);
printf("Children: %s\n", (**node.child).name);
}
int main() {
struct Node n1 = { "Parent", 1, NULL, NULL };
struct Node n2 = { "Child1", 2, &n1, NULL };
*n1.child = &n2;
print(n1);
print(n2);
return 0;
}
Can anybody see what I'm doing wrong here and what I should do instead?
Kind regards,
Edit:
Actually what I wanted to achieve was to create the child member like this (I'm using an example with an array of integers to illustrate what I mean):
int *p = malloc(sizeof(int));
*p =1;
*(p+1)=2;
but instead of p pointing to integers having it point to pointers to struct Node. Is this doable?
You get a segmentation fault because you do not test if the parent node is valid, nor if the child node is a valid pointer, nor that the pointer it points to is valid too. The initialization of n1.child[0] is incorrect too.
*n1.child = &n2; has undefined behavior because n1.child is a null pointer.
printf("Parent: %s\n", (*node.parent).name); has undefined behavior for n1;
printf("Children: %s\n", (**node.child).name); has undefined behavior for n2.
Alos note that it is idiomatic in C to pass structure pointers rather than copies of structures to functions such as print.
Here is a modified version, assuming child, if not NULL points to a NULL terminated array of node pointers.
EDIT: I added an add_child function to illustrate how to construct trees from individual nodes.
#include <stdio.h>
#include <stdlib.h>
struct Node {
char name[10]; // Name of the node.
int data; // The data it holds.
struct Node *parent; // The parent node.
struct Node **child; // if not NULL, points to a NULL terminated array of pointers.
};
void print(const struct Node *node) {
if (node) {
printf("Name: %s\n", node->name);
printf("Data: %d\n", node->data);
if (node->parent) {
printf("Parent: %s\n", node->parent->name);
}
if (node->child) {
printf("Children:");
for (int i = 0; node->child[i]; i++) {
printf("%s %s", i > 0 ? "," : "", node->child[i]->name);
}
printf("\n");
}
}
}
// add a child node to a parent's child list.
// return 0 upon success or an error code on failure
int add_child(struct Node *parent, struct Node *chid) {
if (parent == NULL)
return 1;
if (child == NULL)
return 2;
size_t nchild = 0;
if (parent->child != NULL) {
while (parent->child[nchild] != NULL)
nchild++;
}
struct Node *new_child = realloc(parent->child, (nchild + 2) * sizeof(*new_child));
if (new_child == NULL)
return 3;
parent->child = new_child;
parent->child[nchild++] = child;
parent->child[nchild] = NULL;
child->parent = parent;
return 0;
}
int main() {
struct Node n1 = { "Parent", 1, NULL, NULL };
struct Node n2 = { "Child1", 2, NULL, NULL };
struct Node n3 = { "Child2", 3, NULL, NULL };
add_child(&n1, &n2);
add_child(&n1, &n3);
print(&n1);
print(&n2);
print(&n3);
return 0;
}
You've commented out the print function, but you're trying to call it to print the nodes.
n1.child is NULL pointer, you dereference it here *n1.child = &n2;
this why you get segfault, just make child normal pointer not double pointer it will solve the problem
struct Node {
char name[10]; // Name of the node.
int data; // The data it holds.
struct Node *parent; // The parent node.
struct Node *child; //};
void print(struct Node node) {
printf("Name: %s\n", node.name);
printf("Data: %d\n", node.data);
printf("Parent: %s\n", (*node.parent).name);
printf("Children: %s\n", (*node.child).name);}
int main() {
struct Node n1 = { "Parent", 1, NULL, NULL };
struct Node n2 = { "Child1", 2, &n1, NULL };
n1.child = &n2;
print(n1);
print(n2);
return 0;}

Insert Node into BST on a loop in C

I'm trying to insert into my BST but I'm struggling with creating a loop out of it.
The code works when I insert one by one, but when I try to put it into a loop it doesn't insert correctly.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h> // for strcmp()
#include <ctype.h> // for toupper()
typedef struct BstNode{
//char name[20];
// int data;
struct BstNode* left;
struct BstNode* right;
char* name;
}BstNode;
typedef int (*Compare)(const char*, const char*); // makes comparisons easier
/* Returns pointer address to newly created node */
BstNode* createNode(char* name){
BstNode* newNode = (BstNode*)malloc(sizeof(BstNode)); // Allocates memory for the newNode
newNode->name = name; // newNode->data is like newNode.data
newNode->left= NULL;
newNode->right = NULL;
return newNode;
}
//insert node into Tree recursively
BstNode* insertNode(BstNode* node, char* name, Compare cmp){
int i;
/* char *s1 = node->name;
char *s2 = name;
printf("s1: %s, s2: %s\n", s1,s2);
i = strcmp(s1, s2); // if =1, s1 is greater
printf("i: %d\n", i); */
if(node == NULL){// if tree is empty
// printf("inside NULL\n");
node = createNode(name);
//return node;
}
else{
i = cmp (name, node->name); // sweet
if(i == -1){
// printf("inside left\n");
node->left = insertNode(node->left, name, cmp);
//return node;
}
else if(i == 1){
// printf("inside right\n");
node->right = insertNode(node->right, name, cmp);
//return node;
}
else if(i == 0 ){ //avoid duplicates for now
// printf("inside 0\n");
printf("Name is in BST\n");
return NULL;
}
}
return node;
}
BstNode* printTree(BstNode* node){
if(node == NULL){
return NULL;
}
printTree(node->left);
printf("%s\n",node->name);
printTree(node->right);
}
int CmpStr(const char* a, const char* b){
return (strcmp (a, b)); // string comparison instead of pointer comparison
}
//void Insert(Person *root, char name[20]);
int main(){
BstNode* root = NULL; // pointer to the root of the tree
char buf[100];
char option = 'a';
while(1) {
printf("Enter employee name");
scanf("%s",buf);
printf ("Inserting %s\n", buf);
root = insertNode(root, buf, (Compare)CmpStr);
printTree(root);
}
}
I can do root = insertNode(root, name, (Compare)CmpStr)
several times in code, but if I try to loop it with user input it won't insert correctly. I'm not sure if it has to do with the fact that I'm using scanf() or root not being set correctly. I've tried using fgets() as well but I'm not too sure how to use it and keep messing that up.
Any help is appreciated.
In your loop, you always pass the same buffer to your insert function; Your createNode does not copy the content of the buffer but rather stores a reference to the (always) same buffer; Hence, changing the buffer content after insert will also change the "content" of previously inserted nodes.
I'd suggest to replace newNode->name = name in createNode with newNode->name = strdup(name). This will actually copy the passed "contents" and gives your BST control over the memory to be kept. Thereby don't forget to free this memory when deleting nodes later on.

Is binary tree search lying to me?

Hey I'm trying to write a program that will take a list of strings (these are in order):
polymorphism
object
templates
structure
class
pointer
reference
traversal
inheritance
exceptions
recursive
overloading
And then store these strings in a binary tree and finally do an in-order traversal.
However, I'm having a problem that I just can't figure out. My function to add nodes keeps telling me that I've already added the node but, it never actually gets added?? My output is like this:
ADDED NODE: polymorphism
ERROR: Same Data: object, object
ERROR: Same Data: templates, templates
ERROR: Same Data: structure, structure
ERROR: Same Data: class, class
ERROR: Same Data: pointer, pointer
(etc...)
ERROR: overloading, overloading
ERROR: overloading, overloading
FINISHED BUILDING
overloading
Finally, here's the source code:
#include <stdlib.h>
#include <stdio.h>
struct tree {
char* data;
struct tree *left;
struct tree *right;
};
void buildTree(struct tree**);
void printAlpha(struct tree*);
void insert(struct tree **root, char *n);
int main(int argc, char* argv[]) {
struct tree* myTree = NULL;
buildTree(&myTree);
printf("FINISHED BUILDING\n\n");
printAlpha(myTree);
system("PAUSE");
return 0;
}
/*Builds tree from text file*/
void buildTree(struct tree **root) {
FILE* fIn = fopen("./in.txt", "r");
char* input = (char*) malloc(sizeof(char));
if(!fIn) {
printf("ERROR: Cannot find file\n");
return;
}
while(!feof(fIn) && fscanf(fIn, "%s", input)) {
// printf("INP:%s\n", input);
insert(root, input);
}
}
void insert(struct tree **root, char *n) {
if (*root == NULL) {
// found the spot, create and insert the node
struct tree *newNode = NULL;
newNode = (struct tree*) malloc(sizeof(struct tree) );
newNode->data = n;
newNode->left = NULL;
newNode->right = NULL;
*root = newNode;
printf("ADDED NODE: %s\n", newNode->data);
}
else if(strcmp(n, (*root)->data) < 0)
insert(&((*root)->left), n);
else if(strcmp(n, (*root)->data) > 0)
insert(&((*root)->right), n);
else
printf("ERROR: Same data: %s, %s\n", (*root)->data, n);
}
/*In order traversal*/
void printAlpha(struct tree *root) {
struct tree *curNode = root;
/*If empty something went wrong*/
if(!curNode) {
printf("Error: Binary Tree Is Empty!\n");
// return;
}
if(curNode->left != NULL) {
printAlpha(root->left);
}
printf("%s\n", curNode->data);
if(curNode->right != NULL) {
printAlpha(curNode->right);
}
}
You are creating a single string (char* input = (char*) malloc(sizeof(char));) and overwriting its contents each time. You insert this single string into the tree, then the next time compare it against itself.
Solution: Move the malloc inside the loop.

C segmentation fault in insert to binary tree

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.

Resources