Why does afl fuzzer get segmentation fault? - c

I did a program in c to do some avl sorting. the program runs well when i test it with no crash. however i ran the program for possible bugs with afl fuzzer and i dont seem to know why i keep getting segmentation fault. below is the tree.c. I dont get bugs when i fuzz without my main.c connecting to the tree.c. Only comes when i send inputs to the tree sorter. Some certain inputs brings about this bug. i made changes to memory allocation but still cant figure out why. i used valgrind, cppcheck and dont get any errors on them. Please why does this error happen and how can i fix it?
an example input from the fuzzer that brings code to segmentation fault
i 3o
i 7ÿo
i
i 3ÿo
i3
3
i 3ÿ3
i83 3
i23ÿo
tree.c
#include "tree.h"
Tree* tree_create(){
Tree *tree = malloc(sizeof(Tree));
tree->root = NULL;
return tree;
}
void tree_node_delete(Node* node) {
if (node == NULL) {
free(node);
return;
}
if (node->left) {
tree_node_delete(node->left);
}
if (node->right) {
tree_node_delete(node->right);
}
free(node->name);
free(node);
}
void tree_delete(Tree* tree) {
tree_node_delete(tree->root);
free(tree);
}
void node_insert(Node* node, int age, char* name, int gen) {
if (age <= node->age){
if (node->left == NULL){
Node* newLeft = calloc(1, sizeof(Node));
newLeft->age = age;
newLeft->name = name;
newLeft->parent = node;
newLeft->right = NULL;
newLeft->left = NULL;
newLeft->isRight = false;
node->left = newLeft;
} else {
node_insert(node->left, age, name, node->left->generation);
}
} else {
if (node->right == NULL){
Node* newRight = calloc(1, sizeof(Node));
newRight->age = age;
newRight->name = name;
newRight->parent = node;
newRight->right = NULL;
newRight->left = NULL;
newRight->isRight = true;
node->right = newRight;
} else {
node_insert(node->right, age, name, node->right->generation);
}
}
}
void tree_insert(Tree* tree, int age, char* name) {
if (tree->root == NULL) {
Node *node = calloc(1, sizeof(Node));
node->name = name;
node->age = age;
node->isRoot = true;
node->right = NULL;
node->left = NULL;
tree->root = node;
} else {
node_insert(tree->root, age, name, 1);
}
}
void tree_erase(Tree* tree, int age, char* name) {
Node* data = tree_find(tree, age, name);
if (data == NULL) {
printf("\nThis node doesn't exist in the current tree\n");
} else {
data->name = NULL;
data->age = NULL;
if (data->grandparent) {
if(data == data->grandparent->grandchildRR) {
data->grandparent->grandchildRR = NULL;
} else if(data == data->grandparent->grandchildRL) {
data->grandparent->grandchildRL = NULL;
} else if(data == data->grandparent->grandchildLR) {
data->grandparent->grandchildLR = NULL;
} else if(data == data->grandparent->grandchildLL) {
data->grandparent->grandchildLL = NULL;
}
}
tree_cleanup(tree, &tree->root, tree->root);
}
}
// Will clean the tree to release previously used nodes
void tree_cleanup(Tree* tree, Node** nodeAdress, Node* node) {
if (node->left) {
tree_cleanup(tree, &node->left, node->left);
}
if (node->right) {
tree_cleanup(tree, &node->right, node->right);
}
if(node->age == NULL && node->name == NULL) {
*nodeAdress = NULL;
free(*nodeAdress);
}
if(node->left == NULL && node->grandchildLL) {
node->left = node->grandchildLL;
node->left->parent = node;
node->left->grandparent = node->parent;
if(node->left->left) {
node->grandchildLL = node->left->left;
} else {
node->grandchildLL = NULL;
}
} else if(node->right == NULL && node->grandchildRL) {
node->right = node->grandchildRL;
node->right->parent = node;
node->right->grandparent = node->parent;
node->right->isRight = true;
if(node->right->left) {
node->grandchildRL = node->right->left;
} else {
node->grandchildLR = NULL;
}
} else if(node->left == NULL && node->grandchildLR) {
node->left = node->grandchildLR;
node->left->parent = node;
node->left->grandparent = node->parent;
node->left->isRight = false;
if (node->left->right) {
node->grandchildLR = node->left->right;
} else {
node->grandchildLR = NULL;
}
} else if(node->right == NULL && node->grandchildRR) {
node->right = node->grandchildRR;
node->right->parent = node;
node->right->grandparent = node->parent;
if (node->right->right) {
node->grandchildRR = node->right->right;
} else {
node->grandchildRR = NULL;
}
}
}
//Calculate the weight and the balance factor of the node.
void tree_balance_factor(Tree* tree, Node* node) {
if (node == NULL) {
return;
}
if (node->left) {
tree_balance_factor(tree, node->left);
}
if (node->right) {
tree_balance_factor(tree, node->right);
}
if (node->parent) {
if (node->isRight == true) {
if (node->weightRight > node->weightLeft) {
node->parent->weightRight = node->weightRight+1;
} else {
node->parent->weightRight = node->weightLeft+1;
}
} else if (node->isRight == false) {
if (node->weightRight > node->weightLeft) {
node->parent->weightLeft = node->weightRight+1;
} else {
node->parent->weightLeft = node->weightLeft+1;
}
}
}
node->balancefactor = node->weightRight - node->weightLeft;
if (node->balancefactor == 2) {
if(node->right->balancefactor == 1) {
leftRotation(tree, node);
} else {
rightPermutation(tree, node);
leftRotation(tree, node);
}
} else if (node->balancefactor == -2) {
if(node->left->balancefactor == -1) {
rightRotation(tree, node);
} else {
leftPermutation(tree, node);
rightRotation(tree, node);
}
}
}
// Reset the weightings and set up the grandchilds and grandparents relations back
void tree_balance_factor_reset(Tree* tree, Node* node) {
if (node == NULL) {
return;
}
if (node->left) {
tree_balance_factor_reset(tree, node->left);
}
if (node->right) {
tree_balance_factor_reset(tree, node->right);
}
node->weightLeft = 0;
node->weightRight = 0;
if(node->right) {
if(node->right->right) {
node->grandchildRR = node->right->right;
node->right->parent = node;
node->right->right->grandparent = node;
} else {
node->grandchildRR = NULL;
}
if(node->right->left) {
node->grandchildRL = node->right->left;
node->right->parent = node;
node->right->left->grandparent = node;
} else {
node->grandchildRL = NULL;
}
}
if(node->left) {
if(node->left->left) {
node->grandchildLL = node->left->left;
node->left->parent = node;
node->left->left->grandparent = node;
} else {
node->grandchildLL = NULL;
}
if (node->left->right) {
node ->grandchildLR = node->left->right;
node->left->parent = node;
node->left->right->grandparent = node;
} else {
node->grandchildLR = NULL;
}
}
}
void setGen (Node* node) {
if(node->parent) {
node->generation = node->parent->generation +1;
}
if (node->left) {
setGen(node->left);
}
if (node->right) {
setGen(node->right);
}
}
void leftRotation(Tree* tree, Node* node ) {
Node* newNode = node->right;
if(node->isRoot == true) {
tree->root = newNode;
newNode->isRoot = true;
node->isRoot = false;
newNode->parent = NULL;
} else if (node->isRoot = false){
newNode->parent = node->parent;
if(node->isRight) {
newNode->parent->right = newNode;
} else {
newNode->parent->left = newNode;
}
}
newNode->left = node;
node->parent = newNode;
node->right = NULL;
}
void rightRotation(Tree* tree, Node* node) {
Node* newNode = node->left;
if(node->isRoot == true) {
tree->root = newNode;
newNode->isRoot = true;
node->isRoot = false;
newNode->parent = NULL;
} else {
newNode->parent = node->parent;
if(node->isRight) {
newNode->parent->right = newNode;
} else {
newNode->parent->left = newNode;
}
}
newNode->right = node;
node->parent = newNode;
node->left = NULL;
}
void rightPermutation(Tree* tree, Node* node) {
Node* newNode = node->right;
node->right = newNode->left;
node->right->right = newNode;
newNode->left = NULL;
newNode->parent = node->right;
node->right->parent = node;
}
void leftPermutation(Tree* tree, Node* node) {
Node* newNode = node->left;
node->left = newNode->right;
node->left->left = newNode;
newNode->right = NULL;
newNode->parent = node->left;
node->left->parent = node;
}
void tree_print_node(Node* node){
if (node == NULL) {
printf("null");
return;
}
printf("[");
printf("{\"%d\":\"%s\"},", node->age, node->name);
tree_print_node(node->left);
printf(",");
tree_print_node(node->right);
printf("]");
}
void tree_print(Tree* tree, int printNewline){
if (tree == NULL) {
printf("null");
return;
}
tree_print_node(tree->root);
if (printNewline){
printf("\n");
}
}
Node* node_find(Node* node, int age, char* name) {
int i = strcmp(node->name, name);
if (node->age == age && i == 0) {
return node;
}
if (age <= node->age) {
if (node->left) {
return node_find(node->left, age, name);
} else {
return NULL;
}
} else {
if (node->right) {
return node_find(node->right, age, name);
} else {
return NULL;
}
}
}
Node* tree_find(Tree* tree, int age, char* name) {
if(tree->root != NULL) {
return node_find(tree->root, age, name);
} else {
printf("\nNo node inserted in the tree yet\n");
return NULL;
}
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
#include "tree.h"
int main() {
char* commandBuffer = (char*)malloc(sizeof(char) * 20);
Tree *tree = tree_create();
for(;;) {
if (tree == NULL){
tree = tree_create();
}
tree_balance_factor_reset(tree, tree->root);
tree_balance_factor(tree, tree->root);
tree_balance_factor_reset(tree, tree->root);
printf("\n- Enter <i age name> to insert a node in the tree \n- Enter <e age name> to erase a node \n- Enter <c age name> to check the tree \n- Enter <p> to "
"print the tree \n- Enter <x> the delete the tree \n- Enter <q> to exit the program\n\n" );
fgets(commandBuffer, 20, stdin);
int b = strlen(commandBuffer);
if(b>=19) {
int clearVar;
while (((clearVar = getchar()) != '\n' && clearVar != EOF)) {
}
};
// Quit on EOF or 'q'
if (feof(stdin) || *commandBuffer == 'q' ){
break;
}
tree = handleString(commandBuffer, tree);
};
free(tree);
free(commandBuffer);
return 0;
}
Tree* handleString(char command[], Tree *tree){
if (command == NULL){
fprintf(stderr, "Invalid command; null pointer\n");
return tree;
}
switch(command[0]){
case 'i':
insert(command, tree);
break;
case 'e':
erase(command, tree);
break;
case 'c':
check(command, tree);
break;
case 'p':
tree_print(tree, 1);
break;
case 'x':
tree_delete(tree);
return NULL;
default:
fprintf(stderr, "Invalid command string: %s\n", command);
break;
}
return tree;
}
Tree* insert(char* command, Tree* tree) {
int age;
char* name = malloc(sizeof(char) * 20);
if (2 != sscanf(command, "i %d %19s", &age, name)){
fprintf(stderr, "Failed to parse insert command: not enough parameters filled\n");
// return NULL;
}
if (tree == NULL){
tree = tree_create();
}
tree_insert(tree, age, name);
return tree;
}
int erase(char* command, Tree* tree) {
int age;
char* name = malloc(sizeof(char) * 20);
if (2 != sscanf(command, "e %d %19s", &age, name)){
fprintf(stderr, "Failed to parse erase command: not enough parameters filled\n");
// return 0;
}
tree_erase(tree, age, name);
return 0;
}
void check(char* command, Tree* tree) {
int age;
char* name = malloc(sizeof(char) * 20);
if (2 != sscanf(command, "c %d %19s", &age, name)){
fprintf(stderr, "Failed to parse check command\n");
}
Node* result = tree_find(tree, age, name);
if (result){
printf("\nThe node is present\n");
} else {
printf("\nThe node could not be found\n");
}
}
tree.h
#ifndef C_IMPLEMENTATION_TREE_H
#define C_IMPLEMENTATION_TREE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct Node {
/**
* Left child of this node
*/
struct Node* left;
/**
* Right child of this node
*/
struct Node* right;
/**
* The age of the data in this node
*/
int generation;
int balancefactor;
int weightLeft;
int weightRight;
struct Node* parent;
struct Node* grandparent;
struct Node* grandchildLL;
struct Node* grandchildLR;
struct Node* grandchildRL;
struct Node* grandchildRR;
bool isRight;
bool parentIsRight;
bool isRoot;
int age;
/**
* The name of the data in this node
*/
char* name;
} Node;
typedef struct Tree {
Node *root;
} Tree;
/**
* Create a new tree
* #param age The age value for the first data point
* #param name The name value for the first data point
* #return The root Node of the tree
*/
Tree* tree_create();
/**
* Delete an entire tree. This will delete the passed Node and all children below it
* #param node The root Node of the tree to delete.
*/
void tree_delete(Tree* tree);
/**
* Insert a new data point into the tree
*
* #param tree The root node of the tree
* #param age The age part of the data point
* #param name The name part of the data point
*/
void tree_insert(Tree* tree, int age, char* name);
/**
* Remove a data point from a tree
* #param tree The root node of the tree
* #param age The age part of the data point to delete
* #param name The name part of the data point to delete
*/
void tree_erase(Tree* tree, int age, char* name);
/**
* Prints a tree in the following format:
* [<data>, <left>, <right>]
* where the elements above have the following format:
* <data> {<age:int>: "<name:string>"}
* <left>, <right>: The same format as the root node. When a child node is NULL, the string NULL is to be printed.
*/
void tree_cleanup(Tree* tree, Node** nodeAdress, Node* node);
/**
* Will free and release null nodes.
*/
void setGen(Node* node);
void tree_balance_factor(Tree* tree,Node* node);
void tree_balance_factor_reset(Tree* tree, Node* node);
void leftRotation(Tree* tree, Node* node);
void rightRotation(Tree* tree,Node* node);
void rightPermutation(Tree* tree, Node* node);
void leftPermutation(Tree* tree, Node* node);
void tree_print(Tree *tree, int printNewline);
Node* tree_find(Tree* node, int age, char* name);
#endif //C_IMPLEMENTATION_TREE_H

I managed to reproduce SIGSEGV in gdb. It is hapened in function rightPermutation, which does not check if pointer to left is NULL or not:
void rightPermutation(Tree* tree, Node* node) {
Node* newNode = node->right;
node->right = newNode->left;
In case the node->left is NULL, you will get SIGSEGV on next line:
node->right->right = newNode;
Further, you can see details of the message and data of the Node structure.
Program received signal SIGSEGV, Segmentation fault.
0x000055555555570c in rightPermutation (tree=0x555555758280, node=0x555555758d20) at tree.c:322
322 node->right->right = newNode;
(gdb) p node
$1 = (Node *) 0x555555758d20
(gdb) p *node
$2 = {left = 0x555555758ed0, right = 0x0, generation = 0, balancefactor = 2, weightLeft = 1, weightRight = 3, parent = 0x0, grandparent = 0x555555758b70,
grandchildLL = 0x0, grandchildLR = 0x0, grandchildRL = 0x0, grandchildRR = 0x555555758c00, isRight = false, parentIsRight = false, isRoot = true, age = 0,
name = 0x555555758d00 ""}

Related

How can I delete a node from Binary search tree in C with 2 children

I am trying to create a function that deletes a node from a binary search tree my problem is whenever I delete a root node that has two children it will work but if I insert a node again there is an error in allocating memory(malloc) for the newly added node. I have tried using a debugger it will stuck in malloc and it doesn't tell me why.
Here is my function in deleting a node from the bst
bool delete_node(node * n, int data)
{
if(n == NULL)
return false;
if (n->data == data)
{
if(n->left == NULL && n->right == NULL)
{
free(n);
n->empty = true;
return true;
}
else if(n->left != NULL && n->right == NULL)
{
node * temp = n;
n = n->left;
free(temp);
temp->empty = true;
return true;
}
else if(n->left == NULL && n->right != NULL)
{
node * temp = n;
n = n->right;
free(temp);
temp->empty = true;
return true;
}
else
{
nodelist * inorder_seq = create_nodelist();
get_inorder_seq(inorder_seq, n);
node * ps = get_predecessor(inorder_seq, n);
if(ps == NULL)
ps = get_successor(inorder_seq, n);
int temp_data = n->data;
n->data = ps->data;
free(inorder_seq->list);
free(inorder_seq);
if(temp_data > n->data)
return delete_node(n->left, ps->data);
else
return delete_node(n->right, ps->data);
}
}
else if(n->data < data)
return delete_node(n->right, data);
else if(n->data > data)
return delete_node(n->left, data);
}
Here is my function in inserting a new node
void insert_node(node * root, int data)
{
node * newnode = create_node(data);
recur_insert_node(root, newnode);
}
Here is the function for the recursion of inserting a new node
void recur_insert_node(node * n, node * newnode)
{
if(n->data > newnode->data)
{
if(n->left == NULL || n->left->empty)
{
n->left = newnode;
n->left->empty = false;
}
else
{
recur_insert_node(n->left, newnode);
}
}
else if(n->data < newnode->data || n->right->empty)
{
if(n->right == NULL)
{
n->right = newnode;
n->right->empty = false;
}
else
{
recur_insert_node(n->right, newnode);
}
}
}
here is my node struct
typedef struct _node
{
int data;
struct _node * left;
struct _node * right;
bool empty;
}node;

%s is skipping the entire print line - no user input

What's wrong in my code? I successfully created a tree and everything is working fine except printInorder function and print statement in void main. When I try to print with %s its skipping the entire line.
Can you please help me in resolving this? I even tried fflush but it doesn't help me in my case and I don't try any scanf statement in my code.
struct Tree
{
char data[10];
struct Tree *left;
struct Tree *right;
} * root;
struct Tree *createNode(char data[])
{
struct Tree *node = malloc(sizeof(struct Tree));
strcpy(node->data, data);
node->left = node->right = NULL;
insertTree(node, root, data);
}
void insertTree(struct Tree *currentNode, struct Tree *temp, char data[])
{
char fletter=data[0];
if (fletter=='a'||fletter=='e'||fletter=='o'||fletter=='i'||fletter=='u')
{
if (root == NULL)
{
root = currentNode;
printf("inserted at root");
}
else if (temp->left == NULL)
{
temp->left = currentNode;
printf("data inserted successfully at left");
}
else
{
insertTree(currentNode, temp->left,data);
}
}
else
{
if (root == NULL)
{
root = currentNode;
printf("inserted at root");
}
else if (temp->right == NULL)
{
temp->right = currentNode;
printf("data inserted successfully at right");
}
else
{
insertTree(currentNode, temp->right,data);
}
}
}
void printInorder(struct Tree *tmp)
{
if (tmp == NULL)
return;
printInorder(tmp->left);
printf("%s ",tmp->data);
printInorder(tmp->right);
}
void main()
{
struct Tree *root = createNode("saish");
struct Tree *d1 = createNode("ansha");
struct Tree *d2 = createNode("shish");
printf("%s",root->data);
printInorder(root);
}
createNode function doesn't return anything even though it is defined to do so.
void insertTree(struct Tree *currentNode, struct Tree *temp, char data[])
{
char fletter=data[0];
if (fletter=='a'||fletter=='e'||fletter=='o'||fletter=='i'||fletter=='u')
{
if (root == NULL)
{
root = currentNode;
printf("inserted at root");
}
else if (temp->left == NULL)
{
temp->left = currentNode;
printf("data inserted successfully at left");
}
else
{
insertTree(currentNode, temp->left,data);
return node;
}
}

Generalized Linked List: Adding Child Link whenever an opening bracket occurs

Here is my code for generating a GLL for the string input: a,(b,c),d where (b,c) will be linked as a child at the next link of a.
GLL* generateList(char poly[])
{
GLL* newNode = NULL, *first = NULL, *ptr = NULL;
while (poly[i] != '\0')
{
if (poly[i] == ')')
{
return first;
}
else
{
if (poly[i] != ',')
{
if (poly[i] != '(')
{
newNode = createNode(poly[i], 0);
}
else
{
++i;
newNode = createNode('#', 1);
newNode->dlink = generateList(poly);
}
}
}
if (first != NULL)
{
ptr = first;
while (ptr->next != NULL)
{
ptr = ptr->next;
}
ptr->next = newNode;
}
else
{
first = newNode;
}
i++;
}
return first;
}
And here is the structure I used for each node.
typedef struct gll
{
int tag;
struct gll* next;
char data;
struct gll* dlink;
} GLL;
I am not finding a way to add that child link to the parent link whenever the bracket opens. The programs runs in a loop.
Note: I have declared i=0 as a global variable to hold the position of character.
Edit: Here is the createNode function
GLL* createNode(char value, int flag)
{
GLL* newNode;
newNode = (GLL *) malloc(sizeof(GLL)*1);
newNode->data = value;
newNode->dlink = NULL;
newNode->tag = flag;
newNode->next = NULL;
return newNode;
}
How do I do it then?
You could do something like that:
#include <stdbool.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct gll
{
int tag;
struct gll* next;
char data;
struct gll* dlink;
} GLL;
GLL* createNode(char value, int flag)
{
GLL* newNode = calloc(1, sizeof(*newNode));
if (!newNode)
return NULL;
newNode->tag = flag;
newNode->data = value;
return newNode;
}
void freeList(GLL *list)
{
for (GLL *current_node = list, *temp; current_node; current_node = temp) {
temp = current_node->next;
freeList(current_node->dlink);
free(current_node);
}
}
GLL* generateList(char *poly, size_t *pos)
{
size_t const length = strlen(poly);
GLL *head = NULL;
GLL *tail = NULL;
for (; *pos < length; ++*pos) {
if (poly[*pos] == '(') {
++*pos; // don't have the next called generateList() read '(' again
tail->dlink = generateList(poly, pos);
if (!tail->dlink) {
freeList(head);
return NULL;
}
continue;
}
else if (poly[*pos] == ')') {
return head;
}
else if (isalpha((char unsigned)poly[*pos])) {
if (!head) {
head = tail = createNode(poly[*pos], 0);
}
else {
tail->next = createNode(poly[*pos], 0);
tail = tail->next;
}
continue;
}
else if (poly[*pos] == ',')
continue;
fputs("Format error :(\n\n", stderr);
freeList(head);
return NULL;
}
return head;
}
void printList(GLL *list)
{
for (GLL *node = list; node; node = node->next) {
printf("%c ", node->data);
if (node->dlink) {
putchar('(');
printList(node->dlink);
printf("\b) ");
}
}
}
int main(void)
{
size_t pos = 0;
GLL *list = generateList("a,(b,(c,d,e(f)),g,h),i,j,k", &pos);
printList(list);
putchar('\n');
freeList(list);
}
Output
a (b (c d e (f)) g h) i j k
Also, if flag is true then it means that the data is not to be considered but there is a child list to be linked.
Sorry, but I don't get how there could be a child list if there is no data for the node.

Pointer in function to linked list not updating element in 1 case

I am using a struct like this
struct infoM {
char* direction;
int key;
};
typedef struct nodeM{
struct infoM nodeInfo;
struct nodeM *next;
struct nodeM *prev;
} node;
typedef node list;
I have one function that returns the wanted node by a specific field
node * search(list *l, char* direction) {}
And this is my function to remove elements from the list
int delete(list *l, char* direction) {
node *tmp = search(l, direction);
if (tmp != NULL) {
node *ant = tmp->prev;
node *seg = tmp->next;
if (seg != NULL) {
if (ant != NULL) {
ant->next = seg;
seg->prev = ant;
free(tmp);
return 1;
} else { //prev null
seg->prev = NULL;
*l = *seg;
tmp = NULL;
free(tmp);
return 1;
}
} else { //next null
if (ant == NULL) {
l->nodeInfo.key = somevalue;
l->next = NULL;
l->prev = NULL;
return 1;
} else {
printf("Here is the problem\n");
ant->next = NULL;
free(tmp);
return 1;
}
}
} else { //tmp nulo
perror("Error delete : node null\n");
return 0;
}
}
If I have 4 elements in the list, 1234 and I delete first first element everything is okay and returns 234. If I delete the last element it returns 23 seems to work great. But if I try to delete the last element now the function does nothing despite being the same case that when it is 234 and I don't understand why. The list is not being updated.
In the main I am using the list like this :
list a;
delete(&a, "whatever");
What am I doing wrong ?
This is the code for search
node * createnode(){
node *tmp = (node *) malloc (sizeof(node));
return tmp;
}
node * search(list *l, char* direction) {
node *tmp = createnode();
if (l->nodeInfo.key == 777) {
perror("Error search: empty list\n");
return NULL;
}
tmp=l;
while((strcmp(direction, tmp->nodeInfo.direction) !=0) && (tmp->next != NULL)) {
tmp = tmp->next;
}
if (strcmp(direction, tmp->nodeInfo.direction) == 0) {
return tmp;
} else {
perror("Error search: element not found\n");
return NULL;
}
}

Deleting a node form a binary search tree in C

I am trying to write a function to delete a node(any node) from a binary search tree. For some reason, the delete function deletes multiple nodes. It is a recursive function and I am somewhat confused when it comes to resursion. below is my code, can somebody help me figure out what went wrong.
Thanks in advance
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct node *nodeP;
typedef struct StudentRoster *StudentRosterP;
struct node
{
nodeP left;
char name[30];
int ID;
nodeP right;
};
struct StudentRoster
{
nodeP root;
int size;
};
//create a new student roster
StudentRosterP newStudentRoster()
{
StudentRosterP new;
new = NULL;
new = malloc(sizeof(struct StudentRoster));
if (new == NULL)
{
fprintf(stderr, "Error: Memory allocation for Student Roster failed\n");
return NULL;
}
else
{
new->root = NULL;
new->size = 0;
return new;
}
}
//creates a new node to store student information
nodeP newNode(char *name, int ID)
{
nodeP new;
new = NULL;
new = malloc(sizeof(struct node));
if(new == NULL)
{
fprintf(stderr, "Memory allocation for the node failed.\n");
return NULL;
}
else
{
new->left = NULL;
new->right = NULL;
new->ID = ID;
strcpy(new->name, name);
return new;
}
}
//function to insert student. this is a helper function, recursive call
void insert(nodeP root, int ID, char * name)
{
if (ID == root->ID)
{
printf("Duplicate IDs not allowed\n");
return;
}
else {
if(ID < root->ID)
{
if(root->left == NULL)
{
root->left = newNode(name, ID);
}
else
{
root = root->left;
insert(root, ID, name);
}
}
else
{
if(root->right == NULL)
{
root->right = newNode(name, ID);
}
else
{
root = root->right;
insert(root, ID, name);
}
}
}
}
//to insert new student
void insertStudentRoster(StudentRosterP roster, char * name, int ID)
{
nodeP root = roster->root;
if(roster->root == NULL) // its empty
{
roster->root = newNode(name, ID);
}
else {
if (ID == roster->root->ID)
{
printf("Duplicate IDs not allowed\n");
return;
}
else
{
insert(roster->root, ID, name);
}
}
}
/*
* Helper function for removeStudentRoster
* finds a node to be deleted and returns its pointer
*/
nodeP findMin(nodeP node)
{
while(node->left != NULL)
{
node = node->left;
}
return node;
}
//removes the node to be deleted
//returns null pointer to the parent function
//This is where I am having problem
nodeP delete(nodeP root, int ID)
{
if(root == NULL)
{
return root;
}
else if(ID < root->ID)
{
root->left = delete(root->left, ID);
}
else if(ID > root->ID)
{
root->right = delete(root->right, ID);
}
else
{
if (root->left == NULL && root->right == NULL)
{
free(root);
root = NULL;
}
else if(root->left == NULL)
{
nodeP temp = root;
root = root->right;
free(temp);
}
else if(root->right == NULL)
{
nodeP temp = root;
root = root->left;
free(temp);
}
else
{
nodeP temp = findMin(root->right);
root->ID = temp->ID;
strcpy(root->name, temp->name);
root->right = delete(root->right, temp->ID);
}
return root;
}
}
/*
* Removes the node containing the matching names
* Parameters: StudentRoster, id
*/
void removeStudentRoster(StudentRosterP roster, int ID)
{
if(roster == NULL)
{
printf("The Student roster does not exist\n");
return;
}
else if(roster->root == NULL)
{
printf("The Student roster is empty\n");
return;
}
else{
//find the node to be deleted
roster->root = delete(roster->root, ID);
}
}
//for printing in ordered
void inOrder(nodeP node)
{
if (node == NULL)
return;
inOrder(node->left);
printf("ID #: %i, Name: %s \n", node->ID, node->name);
inOrder(node->right);
}
/*
* Displays all the entries in the Phone book in order
* Display one person per line, ID followed by first name
*/
void displayStudentRoster(StudentRosterP roster)
{
if (roster->root == NULL) {
printf("The Roster is empty");
return;
}
else
{
inOrder(roster->root);
return;
}
}
int main()
{
StudentRosterP newRoster;
newRoster = newStudentRoster();
insertStudentRoster(newRoster, "Alice", 10);
insertStudentRoster(newRoster, "Jake", 8);
insertStudentRoster(newRoster, "josh", 12);
insertStudentRoster(newRoster, "Alen", 9);
insertStudentRoster(newRoster, "Joe", 11);
removeStudentRoster(newRoster, 11); //it removes the whole roster when removing a node that has no childrens
//when removing the root, it also removes the right child
displayStudentRoster(newRoster);
return (EXIT_SUCCESS);
}
In your delete function, your return is misplaced (only reached when ID matches root->ID). You need to move it past the next closing brace to place it after the else it's in:
}
/* "return root;" was here... */
}
return root; /* ..but should be here. */
}
Additionally, the logic seems wrong for deleting the node when ID does match (in that last else). What you need to do is either move the right branch to the rightmost node in the left branch, or the left branch to the leftmost node of the right branch... then return that branch. So using your findMin() to find the leftmost part of the right branch, we can do:
else
{
nodeP temp = findMin(root->right);
temp->left = root->left;
temp = root;
root = root->right;
free(temp);
}

Resources