Segmentation Fault error - binary search tree in C - c

I'm trying to build a binary search tree. Inserting an integer using insert function (only using 1 to 100 for testing) and appending the result to a file using inorder traversal. However, i'm getting a segmentation fault error. Using Visual Studio code on Macbook Pro 2020. Also tested on Codeblocks on Windows - filename.exe stops working and crashes.
#include <stdio.h>
#include <stdlib.h>
typedef struct node *BST;
struct node {
int data;
BST left;
BST right;
};
BST insert(BST root, int number) {
BST temp = NULL;
if (root == NULL) {
temp = *(BST *)malloc(sizeof(BST));
temp->left = NULL;
temp->right = NULL;
temp->data = number;
root = temp;
}
else if (root->data > number) {
insert(root->left, number);
}
else {
insert(root->right, number);
}
return root;
}
//returning null if number not found and pointer to root if found
BST find(BST root, int number) {
if (root == NULL) {
return NULL;
}
if (root->data > number) {
find(root->left, number);
}
else if (root->data < number) {
find(root->right, number);
}
else (root->data = number);
return root;
}
//printing number to file
void inOrder (BST root, FILE *fp) {
if (root == NULL) return;
inOrder(root->left, fp);
fprintf(fp, "%d", root->data);
inOrder(root->right, fp);
}
int main() {
BST root = NULL;
int n = 100;
int treeArray[n];
for (int r = 0; r < n; r++) {
treeArray[r] = r;
}
root = insert(root, treeArray[0]);
for (int x = 1; x < n; x++) {
insert(root, treeArray[x]);
}
FILE *treefile = fopen("print_tree.txt", "w");
inOrder(root, treefile);
fclose(treefile);
return 0;
}
Error: /bin/sh: line 1: 44278 Segmentation fault: 11 *file path redacted*
What am I doing wrong here? :(

Main problem is with this statement:
temp = *(BST *)malloc(sizeof(BST));
As it was already explained in the other answer clearly, I am going to skip that.
So you can do:
temp = malloc(sizeof (struct node));
OR
// to add : this helps in case the type of temp ever changes,
temp = malloc(sizeof(*temp));
Other minor logical changes:
In the find function, there is no need of this else if statement
// = or == doesn't matter now
else (root->data = number);
In the insert function, you forgot to link the nodes which you insert after your root node. So whenever you perform the inorder traversal, you only get the root node i.e 0 in your case.
Note:
typedef is used to make code more readable, but hiding the pointer using typedef creates confusion. So I would suggest not to typedef pointers.

You declare BST as:
typedef struct node *BST;
So, it is a pointer to a struct node and your problem is probably here:
temp = *(BST *)malloc(sizeof(BST));
You are allocating memory but the byte size you specified is that of BST, that is pointer to struct node, while you want to allocate a struct node.
You cast the returned value of malloc to a pointer to a BST, that is, a pointer to a pointer to a struct node. And then you de-reference it to assign the result to temp. So, what you assign to temp is a pointer to a struct node (correct) but the pointed object has the wrong size. Anyway, you should not cast the value returned by malloc (void *).
Things are much simpler than you apparently think: if you want to allocate a struct node (or anything else) pass its size to malloc. malloc returns a void * pointer to the allocated struct node that you can assign to any pointer variable without casting.
Note: you should check the returned value because if malloc fails it returns NULL and you should not use that.
Try this, instead:
temp = malloc(sizeof (struct node));
if(temp == NULL) {
fprintf(stderr, "%s:%d allocation failed\n", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
I assumed that an allocation error, in your case, is unrecoverable, adapt if it is.
Note: you could also, as suggested in comments, use:
temp = malloc(sizeof *temp);
which will always work, by construction. But as long as you are not completely comfortable with pointers and memory allocation I suggest that you use explicit types with malloc. It is a bit easier to read and understand, even if it is a bit less easy to maintain (if you change the type of temp).
But there are other problems with your code. Your insert and find functions are bogus. Understanding why is left as a debugging exercise.

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

Does a node's behaviour change when it is a member of a struct?

I'm trying to learn how to use linked lists, so I've written myself a function to recursively go through a linked list and print a word stored in each node, but it's only printing the penultimate item and then repeating indefinitely. I've debugged this and I can see it's because the last node will satisfy n.next != NULL, so I wanted to change the condition to n != NULL to avoid this, but I get the error message: error: invalid operands to binary expression ('node' (aka 'struct node') and 'void *'). I've tried to search the error message on Google and SO but I can't explain why n.next != NULL compiles nicely but n != NULL doesn't. To me, I'd say n and n.next are both type node, but presumably my intuition is deceiving me somehow. Is it because n.next is a struct member that it's behavior changes, or am I on the wrong track?
I include the code below (function in question is at the bottom):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node
{
char word[20];
struct node *next;
}
node;
void print (node n);
node *table[1];
int main(void)
{
// TODO
char word[20];
FILE *file = fopen("list", "r");
node *first = malloc(sizeof(node));
table[0] = first;
if (file != NULL)
{
while (fscanf(file, "%s", word) != EOF)
{
node *entry = malloc(sizeof(node));
if (entry != NULL)
{
strcpy (entry->word, word);
entry->next = first->next;
first->next = entry;
}
}
}
print(*first);
}
void print (node n)
{
while(n != NULL)
{
printf("%s\n", n.word);
print(*n.next);
}
}
To me, I'd say n and n.next are both type node
Not so; n is a node, but n.next is type node *, i.e. a pointer to a node. Pointers can be null but structs cannot.
Thus the object passed to print is guaranteed valid. (If first were a null pointer then print(*first) would already have crashed, or "caused undefined behavior", before you even entered print.)
It's also not necessary to have a loop in print, since the recursion handles the list traversal. Indeed, if you try to keep the loop as it is, it's an infinite loop, because nothing in the body modifies the value of n.
I would write:
void print (node n)
{
printf("%s\n", n.word);
if (n.next != NULL)
print(*n.next);
}
However this approach is not really idiomatic, and it's also not very efficient, since passing structs by value tends to involve unnecessary copying and stack usage. It'd be more common, as dbush suggests, to have a version that takes pointers:
void print(const node *np)
{
if (np)
{
printf("%s\n", np->word);
print(np->next);
}
}
which you then call as print(first);.
A next good exercise would be to try to write a version of print that doesn't use recursion, since that will allow you to handle very long lists that might exceed your stack size.
there are mainly to problems:
don't forget to initialize the value after malloc, or they can be anything, especially the next will not be NULL as you expected.
node *first = (node*)malloc(sizeof(node));
first->word[0] = '\0';
first->next = NULL;
node *entry = (node*) malloc(sizeof(node));
entry->word[0] = '\0';
entry->next = NULL;
I prefer to use calloc than malloc
node* first = (node*)calloc(1, sizeof(node));
assert(first);
node* entry = (node*)calloc(1, sizeof(node));
assert(entry);
in the function of print
void print (node* n)
{
if(n != NULL)
{
printf("%s\n", n->word);
print(n->next);
}
}
since you call print recursively, if should be used rather than while

Generic list contains garbage values in C

So I wanted to write a function in C which converts a generic array into a single linked list.
The code I wrote:
typedef struct Node {
struct Node* next;
void *value;
} Node;
void insert(Node** root, void* value) {
Node* new_node = (Node *) malloc(sizeof(Node));
Node* ptr;
new_node->value = value;
new_node->next = NULL;
if (*root == NULL)
*root = new_node;
else {
ptr = *root;
while (ptr->next != NULL)
ptr = ptr->next;
ptr->next = new_node;
}
}
Node* arr2list(void* array, size_t length) {
Node *root = NULL;
for(int i = 0; i < length; i++) {
insert(&root,&array[i]);
}
return root;
}
I wrote a small test for it:
int main() {
int arr[] = { 1, 2, 3, 4, 5 };
int n = sizeof(arr) / sizeof(arr[0]);
Node* root = arr2list(arr, n);
while (root != NULL)
{
printf("%d,",*(int*) root->value);
root = root->next;
}
return 0;
}
But I get garbage values: -13308,-2145276560,-2145276560,-2145276560,-2145276560,.
I can't seem to find the mistake that leads to those results.
What could be the issue?
Your program contains &array[i] where array has type void* at line 28.
This is not standard C. GCC accepts it and treats the pointer arithmetic as char* arithmetic (arguably a bad idea, in particular because it feeds the confusion in an example such as this one).
Since your function arr2list consumes the array through some misaligned pointers, the results are apparently arbitrary values (that contain some of the bytes of the first array element and some of the bytes of the second array element, for instance).
I would be happy to say that the function arr2list must simply take as argument the length of one element, but this small change alone is not going to be enough in itself to make things work. Your linked list type stores pointers as data, so the function will also need to allocate a block for each of the elements, and store a pointer to this element inside the Node.
If you are content with making the list point to the elements of the array, then forget the above paragraph, you almost have a working solution, just make arr2list take an extra argument size_t elt_size and use (char*)array + elt_size*i instead of &array[i].

I keep getting a segmentation fault here. Been at this for 4 hours

I really need some help here because I have been trying to find a solution to this for hours and nothing works.
I have these two structs:
typedef struct NODE {
char* line;
int count;
struct NODE *left, *right;
} NODE;
typedef struct BST {
NODE *root;
} BST;
And these lines of code which appear suspiscious:
if (iflag == 0) {
char curr_string[300];
BST binary_tree;
//fpointer_in = fopen(filename_in, "r");
//while (!feof(fpointer_in)) {
//fgets(curr_string, 300, fpointer_in);
addTreeNode("Hello There!", binary_tree.root); // Adds the node to the binary tree.
//}
NODE *cpy = malloc(sizeof(NODE));
cpy->line = calloc(25, sizeof(char));
cpy->count = 0;
cpyNode(cpy, binary_tree.root);
free(cpy);
free(binary_tree.root);
//printf("%s\n", cpy->line);
//free(binary_tree.root);
//fclose(fpointer_in);
}
This is the addTreeNode function:
void addTreeNode(char* line_string, NODE* root) {
if (root == NULL) {
root = calloc(25, sizeof(char)); // 25 is a test var.
root->line = calloc(25, sizeof(char)); // 25 is a test variable.
strcpy(root->line, line_string);
root->count = 0;
}
else {
NODE *add_node = malloc(sizeof(NODE));
add_node->line = calloc(25, sizeof(char)); // 25 is a test variable.
strcpy(add_node->line, line_string);
while (root != NULL) {
if (strcmp(line_string, root->line) < 0 && root->left == NULL) {
//cpyNode(node_ptr->left, add_node);
}
}
}
}
The if block in the addTreeNode function has been tested but I have yet to test the else block. Regardless, it is never used so I don't think it's an issue.
The issue here is that I am getting a segmentation faule BEFORE the program even reaches main. When I comment out the cpyNode(cpy, binary_tree.root); statement, then it works. I then proceeded to comment out the entire cpyNode funcition minus the first line. I figured out that the first line is giving me a segmentation fault and I can't figure out why. Some help would be greatly appreciated.
You may have other errors, but these are problems you need to address:
if(iflag == 0){
char curr_string[300];
BST binary_tree;
Here, binary_tree is uninitialized.
addTreeNode("Hello There!", binary_tree.root);
//Adds the node to the binary tree.
You expect this call to add a node to the tree, but you are passing the uninitialized root member in by value, and so the pointer will retain its uninitialized state after the function call returns.
You should modify your addTreeNode function to accept a pointer to a BST, and pass the address of binary_tree to the function.

Recursion in C with an array inside and an index

I am trying to do a function that receives the root of a supposed BST and I want to know if the tree in question is a BST.
Problem is that, I am traveling the tree with recursion and what I'm trying to do is, put inside an array all the values of the tree. I searched for how to put a BST into an array (AddtoArray), but the answers I've found on stackoverflow and other websites didn't solve my problem. (I got seg fault).
Here's what I got so far:
#include<stdio.h>
#include<stdlib.h>
struct node{
int key;
struct node *left, *right;
};
struct node *newNode(int item){
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
struct node* insert(struct node* node, int key){
if(node == NULL) return newNode(key);
if(key < node->key)
node->left = insert(node->left, key);
else if(key >= node->key)
node->right = insert(node->right, key);
return node;
}
void check(struct node *root, int *array, int i){
if(root != NULL){
check(root->left, array, i);
array[i++] = root->key;
//I tried to put i++, ++i in every place of this function (trying table test) and I realized it was too difficult to realize what to do here, I've found some functions returning an integer, the "i" in question, but they didn't work out for me.
check(root->right, array, i);
}
}
int main(){
int *array;
int array_length = sizeof(array)/sizeof(array[0]);
int i = 0;
array = (int*)malloc(array_length*sizeof(int));
struct node *root = NULL;
root = insert(root, 50);
insert(root, 30);
insert(root, 20);
insert(root, 40);
insert(root, 70);
insert(root, 60);
insert(root, 20);
check(root, array, i);
printf("PRINTING ARRAY TO SEE IF THE BST IS IN ARRAY:\n");
for(i = 0; i < array_length; i++){
printf("VALUE: %d ", array[i]);
}
free(array);
return 0;
}
I'd like to solve this problem WITHOUT using global variables. How can I do it?
I see two issues in your check-code and its usage (did not analyse the other functions):
First, your malloc does not work as intended, because sizeof(array)/sizeof(array[0]) will always give the same (small) value, probably 1 or 2, regardless of the size of your BST.
So you'd rather introduce a function getting the number of nodes and use this as the length for your array:
int array_length = getNrOfNodes(root); // function to be coded
int *array = malloc(array_length*sizeof(int));
Second, you pass an integral value i by value to a recursive function. As it is passed by value, any i++ will take effect only for the respective function call instance, but will not influence the other ones on the call stack. So it is very likely that the keys of the complete left part of your tree (the one before i is altered), will be written to array[0].
I'd suggest to share the array index among the function instances on the call stack. This can be achieved by passing a pointer to some i rather than passing i-s value around. And I'd introduce an internal version that does the work, because the user of the function needs not to be aware of the helper variable i:
void writeToArray_internal(struct node *root, int *array, int *i){
if(root != NULL){
writeToArray_internal(root->left, array, i);
array[*i] = root->key;
(*i)++;
writeToArray_internal(root->right, array, i);
}
}
void writeToArray(struct node *root, int *array) {
int i=0;
writeToArray_internal(root, array, &i);
}
This line here
int array_length = sizeof(array)/sizeof(array[0]);
is wrong. This only works with pure arrays, because sizeof returns the amount
of bytes of the expression/variable. Your variable array is a pointer, so
sizeof array returns you the size of a pointer and it doesn't matter where the
pointer is pointer, you always will get the same size.
Besides trying to get the number of elements of the "array" before knowing how
many nodes you have, makes no sense, because the number of elements that you need in array depend on the number of nodes, so
you've got write a function that returns you the number of nodes and then
you can allocate space for array.
Also note that your check function is not correct either. The variable i is
local to every call of check so you are going to overwrite values of the
array, because the i++ of the n-th iteration only affects the i of the
n-the iteration, the n-1-th iteration does not see that change and thus
overwrites the value of the n-th iteration.
You'll need to pass i as a pointer as well:
void check(struct node *root, int *array, size_t *i, size_t maxlen) {
if(root != NULL){
check(root->left, array, i, maxlen);
if(*i < maxlen) // checking that you don't step out of bounds
array[(*i)++] = root->key;
check(root->right, array, i, maxlen);
}
}
and the you call it like this:
size_t i = 0;
size_t nodes_number = get_number_of_nodes(root); // you have to write this function
int *array = malloc(nodes_number * sizeof *array);
if(array == NULL)
{
// error handling
// do not continue
}
check(root, array, &i, nodes_number);

Resources