Segmentation Fault - Displaying Tree - c

I get a segfault when calling viewTree(root);
struct treeElement {
unsigned long weight;
unsigned short id;
char chr;
struct treeElement *lchild, *rchild, *parent;
};
typedef struct treeElement node;
node *root;
//INITIALIZE TREE
void initTree() {
root = malloc(sizeof(node));
currentNYT = root;
} //initTree
//VIEW TREE
void viewTree(node *tree) {
printf("%5d%5d%5d%5d%5c%lu", tree->id, tree->parent->id, tree->lchild->id, tree->rchild->id, tree->chr, tree->weight);
viewTree(tree->lchild);
viewTree(tree->rchild);
}
//ADD NODE
void addNode(char newNodeChr) {
node *newNYT, *newExternal;
newNYT = malloc(sizeof(node));
newNYT->id=maxNodes-idCount; idCount++;
newNYT->chr='\0';
newNYT->weight=0;
newNYT->parent=currentNYT;
newNYT->lchild=newNYT->rchild=NULL;
newExternal = malloc(sizeof(node));
newExternal->id=maxNodes-idCount;
newExternal->chr=newNodeChr;
newExternal->weight=1;
newExternal->parent=currentNYT;
newExternal->lchild=newExternal->rchild=NULL;
currentNYT->lchild = newNYT;
currentNYT->rchild = newExternal;
currentNYT=newNYT;
} //addNode
int main()
{
initTree();
addNode('a');
addNode('b');
viewTree(root);
getchar();
return 0;
}

Does the root node have a parent? Do the child leaf nodes have left and right children?
I think most of your problem lies in your printf statement - you don't check whether or not any of the objects you're accessing actually exist before you try to print their ids. Add some if statements in there and see if it helps.

In your viewTree(node *tree) you are not checking if tree is null or not. Definite recipe for segfault when you try to access tree->id when tree is null.
null will be passed for a subtree in a recursive call eventually.
EDIT: In general you have check for null every time you need to access a member of an object. So, tree != null before reading tree->id and tree->lchild != null before reading tree->lchild->id must be ensured.

Don't just allocate the root node, but initialize it, especially the pointers to siblings and to parent (set them to NULL). You are using the uninitialized pointers when adding nodes.

Related

Why does my Recursion using Pointer in C crash?

I'm currently studying Computer Science and we started working with Pointers. I had the feeling that I started to understand pointers but I ran into a problem and can't figure out what went wrong.
We defined a Tree like this:
typedef struct node *tree;
struct node {int key; tree left, right;};
Now we should write a function that creates nodes with three parameters, the key of the node, the left node and the right node that should be "below" the node. I did it like this and it seemed to work:
tree createNode(int n, tree l, tree r){
tree node = (tree) malloc(sizeof(tree));
node->key = n;
node->left = l;
node->right = r;
return node;
}
Finally we should write a function that multiplies all leaves of the Tree and i thought the easiest way would be to start at the root and search for the leaves through a recursion and then multiply them. But when i call the function the program seem to crash in the middle of the function. My function looks like this:
int leafprod(tree t){
printf("%d\n", t->key);
if (t->left == NULL){
if (t->right == NULL){
printf("$1\n\n");
return t->key;
}
printf("$2\n\n");
return leafprod(t->right);
}
if (t->right == NULL){
printf("$3\n\n");
return leafprod(t->left);
}
printf("$4\n\n");
return leafprod(t->left) * leafprod(t->right);
}
and i call the function in the main function like this:
int main(){
tree a = createNode(1, NULL, NULL);
tree b = createNode(2, NULL, NULL);
tree c = createNode(3, a, NULL);
tree d = createNode(4, b, c);
int n = leafprod(d);
printf("end: %d", n);
free(a);
free(b);
free(c);
free(d);
return 0;
}
I used the print statements to follow the programm and try to locate the error, but in most cases it prints nothing. Then sometimes it prints:
4
$4
2
$2
And only two times the program went through the whole code. I believe maybe I am using the malloc function wrong but I cannot tell.
The problem is in this line:
tree node = (tree) malloc(sizeof(tree));
tree is typedef for a pointer to struct node.
Therefore sizeof(tree) is just the size of the pointer.
You should one of the following instead:
tree node = malloc(sizeof(*l));
Or:
tree node = malloc(sizeof(*r));
*l and *r are of type struct node (not a pointer) and this is the element you are trying to create.
Another option as #IanAbbott commented is:
tree node = malloc(sizeof(*node));
Note that node here is the name of the variable, not the type (which in C requires to be prefixes with struct, i.e. struct node).
The advantage of this approach is that the statement is not dependent on other variables.
Side notes:
You shouldn't cast the result of malloc. See here:Do I cast the result of malloc?.
It's not a good practice to hide pointer types with typedefs. You can consider to avoid it (you can use typedef struct node Node if you want to save the need to use the struct keyword everywhere).
Don't use the typedef for hiding pointer types.
With typedef struct node *tree; you have no idea what tree is in your code hence the confusion.
Typically here tree node = (tree) malloc(sizeof(tree)) you did it wrong, and the main reason was probably because you didn't know anymore what tree actually was.
...
struct node
{
int key;
struct node* left;
struct node *right;
};
struct node* createNode(int n, struct node*l, struct node*r) {
struct node* node = malloc(sizeof(*node)); // don't use the cast, it's useless
...
}
int leafprod(struct node* t) {
...

Add node to multilevel linked list

I apologize for this noob question but I'm really struggling with this. I have a linked list with two different links: Next and sort. I want to add to the front with next but add in increasing order to sort. However whenever I try and add to sort I get a segfault and I'm not sure how I'm supposed to access them in a way that they act as two distinct linked lists with the same data but in a different order.
this is my list:
typedef struct NODE {
value_t value;
key_t key;
struct NODE * next;
struct NODE * sort;
} Node;
and this is how I'm trying to write to it
Node * add_sorted(Node ** head, int value, key_t key){
Node *new_node = malloc(sizeof(Node));
if (new_node != NULL) {
new_node->sort->value = value;
new_node->sort->key = key;
new_node->sort = *head;
*head = new_node;
}
return new_node;
}
thank you in advance for enduring my ignorance
You are trying to assign value to somewhere that you did not initialize in address space.
new_node->sort->value = value;
new_node->sort->key = key;
In this part, you did not create *sort but it is declared like it is there. Creating new_node does not mean there is a *sort. Because it is a pointer. In this case, it does not point anywhere but void.
I do not know if it is related to your problem but I think you need to solve that one too.
Hope it helps.
In adding, new_node->sort = *head; doesn't have any sense. Because, previous setting of attribute sort will be erased.
first you are assigning value to a pointer without allocating memory for it or initializing it.
this should work:
if (new_node != NULL) {
new_node->sort = malloc(sizeof(Node));
new_node->sort->value = value;
new_node->sort->key = key;
new_node->sort = *head;
*head = new_node;
}
also note that your function argument int value has different type from the member you are assigning it to.(value_t value)
also I think here new_node->sort = *head; you meant new_node->next = *head; ,because with this assignment data ,you assigned to fields of sort will be lost.

In-order traversal deviating to other locations in memory

I'm trying to do an in-order traversal on a BST. In the first call of inOrder() everything works as expected: *node points to the root and in the debugger I can see that the whole three is represented correctly (i.e., the root's descendants are correctly represented).
However, in the next call on the left child of the root (i.e., *node now represents the root's left child), the tree is not represented correctly anymore. The only things that are correct are the value of *node and the right child being NULL. The left child is not the node with the value 3 that was appended before, but it has some weird values - it appears to point at a random memory location.
(If I run further, Xcode terminates saying: EXC_BAD_ACCESS...)
Can you explain me why this is so?
#include <stdio.h>
typedef struct Node Node;
struct Node
{
int value;
Node *left;
Node *right;
};
void inOrder(Node *node)
{
if(node!=NULL)
{
inOrder(node->left);
printf("%d,", node->value);
inOrder(node->right);
}
}
void append(Node *root)
{
Node n = {3,NULL};
root->left->left = &n;
}
int main(int argc, const char * argv[])
{
Node a = {10, NULL};
Node b = {5, NULL};
Node root = {8, &b, &a};
// appends a node with value 3 to the node 5 (just a test)
append(&root);
inOrder(&root);
puts("\n");
}
Inside append() function,
void append(Node *root)
{
Node n = {3,NULL};
root->left->left = &n;
}
you're trying to return the address of a local variable n from the function. Outside append(), the address of n is invalid. Using that invokes undefined behaviour.
Solution: Define n as a pointer of type Node, allocate memory dynamically using malloc() and then you can return the pointer. The lifetime of dynamically allocated memory remains valid until deallocated.
root->left->left = &n;
The variable n is local to the function append() and once you exit the function append() n is no more valid.
So accessing the variable out of its scope leads to undefined behavior

Creating a linked list in C

I am currently trying to make a linked list and initialize it within a function. It looks like this:
void add_forest(node_t *head, unsigned char value)
{
int key;
node_t *current = head;
while (current->next != NULL)
{
current = current->next;
}
}
int main()
{
node_t *head;
*head = init_forest(); //error here
}
I am currently getting a segfault at the following area in my code and can not figure out why. I am creating the head in init_forest() and then passing back in the main. When I go through the init_forest() the tree does become built. Any suggestions?
The immediate problem is in main():
node_t *head;
*head = init_forest();
head is an uninitialized pointer; you can't dereference it, and you don't actually want to. You should be using:
node_t *head = init_forest();
But you then need to ensure that init_forest() returns a node_t *, rather than a node_t value. This is the more orthodox style for such linked list management functions. You allocated the structure in the function; if you return a copy of the structure rather than a pointer to the structure, you're leaking memory (and you end up with other problems later).

Binary Search Tree insertion not working when inserting nodes using while loop

I have posted the link to my BST code on ideone: http://ideone.com/P7850n
In the main function I am getting an error when I read values in the while loop and insert into BST, but it works fine if I use a for loop. What could be the possible explanation for this error which occurs only with the while loop ?
#include <stdio.h>
#include <stdlib.h>
//data struct for BST node
typedef struct BST
{
int data;
struct BST *left;
struct BST *right;
}node;
//make node from given data
node* makeNode(int data)
{
node *n=(node*)malloc(sizeof(node));
n->data=data;
n->left=NULL;
n->right=NULL;
return n;
}
//insert node in BST
node* insert(node* root,int key)
{
if(root==NULL)
return makeNode(key);
if(key < root->data)
root->left=insert(root->left,key);
else
root->right=insert(root->right,key);
return root;
}
//inorder printing prints in sorted order
void inorder(node* root)
{
if(root==NULL)
return;
inorder(root->left);
printf("%d ",root->data);
inorder(root->right);
}
//driver function
int main(void) {
// your code goes here
node *root;
int s,i,key;
scanf("%d",&s);
while(s--)
//for(i=0;i<s;i++)
{
scanf("%d",&key);
root=insert(root,key);
}
inorder(root);
return 0;
}
Most probably this is an uninitialized variable root.
The compiler re-uses the same memory for variables, either declared in your program or used internally, after they are not anymore needed, so that other variables later occupy the same memory. In C (unlike, say, Perl), when memory is assigned to a variable, it is not automatically cleared: you should do it yourself, which is called initialization: typically as soon as you declare a variable, you should assign it some value: int year = 2014;. If you use a variable before you assign it a value, it's value will be whatever happens to be in memory that it occupies, left from other variables or even other running programs.
In your case, when you initialize the for loop with i=0, this 0 probably uses the memory later used for root, so accidentally it works. When you initialize the while loop with non-zero s, root uses memory that happens to be non-zero.
The solution is to initialize root = NULL;, and in general it's a good habit to always initialize all variables.
Without node *root = NULL; you are trying to access undefined memory address as root will contain any random data. So you can get valid behavior or any other behavior including crash.
As root is not initialized in inser() function if(root==NULL) may or may not be true and hence you will get different behavior.
This has nothing to do with for or while loop.
its always to initialize any memory variable to NULL or any other variable to 0,while writing any piece of code,otherwise you will always get any unpredictable crash or result.
like in this case,do like this below:
node *root;
int s,i,key;
to
node *root = NULL;
int s =0;
int i = 0;
int key= 0;

Resources