I want to insert data to the tree using this function:
struct treeNode{
data* val;
struct treeNode *left, *right, *parent;
};
void insert(data *d, struct treeNode **leaf, struct treeNode **leaf_par)
{
if( *leaf == 0 )
{
*leaf = (struct treeNode*) malloc( sizeof( struct treeNode ) );
(*leaf)->val = d;
/* initialize the children to null */
(*leaf)->left = 0;
(*leaf)->right = 0;
/* initialize the parent */
(*leaf)->parent = *leaf_par; //here I receive segmentation fault
}
else if(strcmp(d->name, (*leaf)->val->name) < 0)
{
insert( d, &(*leaf)->left, &(*leaf) );
}
else if(strcmp(d->name, (*leaf)->val->name) > 0)
{
insert( d, &(*leaf)->right, &(*leaf) );
}
}
In main I have:
struct treeNode *root = NULL;
data d1 = {"Smith"};
insert(&d1, &root, NULL);
Segmentation fault is there:
(*leaf)->parent = *leaf_par;
At first time *leaf_par is NULL and I don't know why it's not running correctly. How should I fix my insert function? Without "parent" pointer it's easy, but I have to do that with "parent" and it's not working.
You are trying to dereference NULL; don't do that.
A simple fix for your first insert is:
insert(&d1, &root, &root);
Deeper inserts into the recursion will fix the pointer.
Related
When I call insert(element) function and add element, it gives an error as programme has stopped working.
It gives an error when i add 3rd element in left of root or add an element in right side of root.
please help to solve it.
void insert(int iElement){
if(sRoot==NULL){ //Initially sRoot is NULL
sRoot=(struct Node*)malloc(sizeof(struct Node));
sRoot->iData=iElement;
sRoot->sLeft=NULL;
sRoot->sRight=NULL;
}
else{
struct Node *current=(struct Node*)malloc(sizeof(struct Node));
current->iData=iElement;
current->sLeft=NULL;
current->sRight=NULL;
struct Node *parent;
struct Node *temp;
parent=sRoot;
while(parent!=NULL){
temp=parent;
if(iElement>parent->iData){
parent=parent->sRight;
}
if(iElement<parent->iData){
parent=parent->sLeft;
}
}
if(iElement<temp->iData)
temp->sLeft=current;
else
temp->sRight=current;
}
}
There are two bugs in the function the first is that in the loop there are used two if statements instead of if-else if statements.
while(parent!=NULL){
temp=parent;
if(iElement>parent->iData){
parent=parent->sRight;
}
if(iElement<parent->iData){
parent=parent->sLeft;
}
}
So if the first if statement was executed then parent can be set to NULL. However in the second statement you are trying to access the data member iData for such a NULL pointer.
So there must be at least
while(parent!=NULL){
temp=parent;
if(iElement>parent->iData){
parent=parent->sRight;
}
else if(iElement<parent->iData){
parent=parent->sLeft;
}
}
The second problem with this loop is if the used will supply a duplicate value then this loop will be infinite because the pointer parent is not changed.
Also there will be a memory leak because the memory was already allocated for the pointer current though neither node shall be appended in case of a duplicate value.
So you need to process the case when the user supplied a duplicate value.
The function can be implemented the following way as it is shown in the demonstrative program.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int iData;
struct Node *sLeft;
struct Node *sRight;
};
struct Node *sRoot = NULL;
int insert( int iElement )
{
int success = 1;
struct Node **current = &sRoot;
while ( success && *current != NULL )
{
if ( iElement < ( *current )->iData )
{
current = &( *current )->sLeft;
}
else if ( ( *current )->iData < iElement )
{
current = &( *current )->sRight;
}
else
{
success = 0;
}
}
if ( success )
{
*current = malloc( sizeof( struct Node ) );
success = *current != NULL;
if ( success )
{
( *current )->iData = iElement;
( *current )->sLeft = NULL;
( *current )->sRight = NULL;
}
}
return success;
}
int main(void)
{
insert( 10 );
insert( 9 );
insert( 11 );
insert( 12 );
insert( 8 );
insert( 7 );
return 0;
}
Take into account that it is a bad idea when a function depends on global variables.
So it is better to declare it like with one more parameter
int insert( struct Node **sRoot, int iElement );
Here is the modified one, explaination I kept in comments.
void insert(int iElement){
if(sRoot==NULL){ //Initially sRoot is NULL
sRoot=(struct Node*)malloc(sizeof(struct Node));
sRoot->iData=iElement;
sRoot->sLeft=NULL;
sRoot->sRight=NULL;
}
else{
struct Node *current=(struct Node*)malloc(sizeof(struct Node));
current->iData=iElement;
current->sLeft=NULL;
current->sRight=NULL;
struct Node *parent;
struct Node *temp;
parent=sRoot;
while(parent!=NULL){ /* it fails when parent is NULL */
if(iElement > parent->iData){
if(parent->sRight ! = NULL)/* need to check if parent->right is null or not */
parent->sRight = current;/*if not NULL then put i
t here */
else
parent = parent->sRight;/* update the parent */
}
if(iElement < parent->iData){
if(parent->sLeft ! = NULL)
parent->sLeft = current;
else
parent=parent->sLeft;
}
}
}
}
Given the following structs:
struct TElem {
int val;
};
typedef int TKey;
struct Node {
TKey key;
struct TElem *elem;
struct Node *left;
struct Node *right;
};
struct bst {
struct Node *root;
};
And the two functions bst_Search and bst_Insert.
struct TElem* bst_Search(struct bst *T, TKey c, struct Node **posins)
{
struct Node *q = T->root;
posins = &(T->root); // (1)
while (q)
if (q->key == c)
return q->elem;
else if ( c < q->key) {
q = q->left;
posins = &(q->left);
} else {
q = q->right;
posins = &(q->right);
}
return NULL;
}
void bst_Insert(struct bst *T, TKey c, struct TElem *x)
{
struct Node **posins;
struct TElem *v;
posins = malloc(sizeof *posins);
v = bst_Search(T, c, posins); // (2)
if (!v) {
struct Node *q = malloc(sizeof *q);
q->key = c;
q->elem = x;
q->left = NULL;
q->right = NULL;
*posins = q; // (3)
} else {
printf("Key exists %d\n", c);
}
free(posins);
}
And main() is "mainly"
struct bst *T = malloc(sizeof *T);
T->root = NULL;
struct TElem *x = elem_New(10);
bst_Insert(T, c, x);
I'm trying to insert a new element (elem_New is working fine) into a BST, using a helper function bst_Search to return a pointer to the right place to insert. (1) is called in first pointing posins to T->root memory address. (as far as I could debug this is working fine).
Then posins address returns to caller function bst_Insert, since bst_Search found a place for it returning NULL at (2). It goes inside the if statement sets q correctly. Then at (3), I expect that where posins is pointing to (in this case the address of where T->root is pointing too) now should be redirected to the new tree node q. The equivalent to T->root = q, but using this call by reference.
because your "posins" isn't change when out your "bst_Search"
void test(int *p){
// g_c is a gobal int
p = &g_c;
printf("%X ",p);}
do your think when call test(int *p)
the value of p will change to point the g_c? no, because the p is only a parameter and it don't change it value when out the proc
my english is poor so i just hope the e.g. code will help your understand~ :)
The way you were updating the q is wrong. Let us say that the tree is like this:
Now let us say you search for 10, bst_search(10) (I have removed your parameters for sake of simplicity and understanding)
Then, this is what you did:
posins = 5 // I am writing numeric values instead of addresses for understanding
// Now
10 > 5
p = p->right // => p = 12
posins = p->left // => posins = 9, cause p is pointing to 12
Again, 10 < 12
So, p = p->left; // => p = 9
posins = p->left; // posins = NULL
This is where it goes wrong, you should have pointed to 9, but you are pointing to the left of 9, This is what you should've coded:
struct TElem* bst_Search(struct bst *T, TKey c, struct Node **posins)
{
struct Node *q = T->root;
posins = &(T->root); // (1)
while (q)
if (q->key == c)
return q->elem;
else if ( c < q->key) {
q = q->left;
posins = &q;
} else {
q = q->right;
posins = q;
}
return NULL;
}
Please comment for any further doubts.
The main problem is that calling arguments can not be updated by operations like posins = &(T->root);.
93) A function may change the values of its parameters, but these
changes cannot affect the values of the arguments. On the other hand,
it is possible to pass a pointer to an object, and the function may
change the value of the object pointed to.
So, if you want to change the calling variable as a value as P it must be *P.
i.e. struct Node **posins should be struct Node ***posins.
The overall code is shown below as a sample.
#include <stdio.h>
#include <stdlib.h>
struct TElem {
int val;
};
typedef int TKey;
struct Node {
TKey key;
struct TElem *elem;
struct Node *left;
struct Node *right;
};
struct bst {
struct Node *root;
};
int TKeyCmp(TKey a, TKey b){
/* return value :
** a = b : 0
** a > b : positive value
** a < b : negative value
*/
return a < b ? -1 : a > b;
}
struct TElem *elem_New(int value){
struct TElem *ep = malloc(sizeof(*ep));//check omitted
ep->val = value;
return ep;
}
void elem_free(struct TElem *ep){
free(ep);
}
void print(struct Node *np){
if(np){
print(np->left);
printf("(%d, %d)", np->key, np->elem->val);
print(np->right);
}
}
struct TElem *bst_Search(struct bst *T, TKey c, struct Node ***posins){
*posins = &T->root;
while (**posins){
int cmp = TKeyCmp(c, (**posins)->key);
if(cmp == 0)
return (**posins)->elem;
else if ( cmp < 0)
*posins = &(**posins)->left;
else
*posins = &(**posins)->right;
}
return NULL;
}
void bst_Insert(struct bst *T, TKey c, struct TElem *x){
struct Node **posins;
if (!bst_Search(T, c, &posins)) {
struct Node *q = malloc(sizeof *q);
q->key = c;
q->elem = x;
q->right = q->left = NULL;
*posins = q;
} else {
elem_free(x);//avoid memory leak
printf("Key exists %d\n", c);
}
}
int main(void){
struct bst *T = malloc(sizeof(*T));
T->root = NULL;
bst_Insert(T, 5, elem_New(10));
bst_Insert(T, 1, elem_New(21));
bst_Insert(T, 9, elem_New(42));
bst_Insert(T, 1, elem_New(99));//Key exists 1
print(T->root);//(1, 21)(5, 10)(9, 42)
//release bst
}
So, I'm doing an assignment for a class in college and the objective is to construct a BST of strings that read a text, divides it and insert each word in the Tree.
But I'm getting a segmentation fault when trying to insert a word (manually), can you guys show me where I did wrong and suggest a repair?
/* Structure for the node */
typedef struct node {
char *key;
int multi;
struct node *left, *right;
} node;
node *root;
void Insert(char *x, node *p){
p = root;
/* if the pointer points to null, create a new node and insert the key */
if (*p == NULL){
(*p) = (node)malloc(sizeof(node))
(*p)->key = strcpy((*p)->key, x);
(*p)->left = NULL;
(*p)->right = NULL;
return;
}
else if (strcasecmp(x, p->key) < 0)
{
Insert(x, &p->left);
return;
}
else if (strcasecmp(x, p->key) > 0)
{
Insert(x, &p->right);
return;
}
/* if the words are equal, add 1 to the multi (how many times the word appears */
else
(*p)->multi = multi + 1;
}
This is the problematic statement: (*p)->key = strcpy((*p)->key, x); You allocated memory only for node but the pointer key is still uninitialized. You need to allocate memory for key also, something like (*p)->key = malloc(strlen(x) + 1);.
I'm trying to pass a pointer to a queue into the createQueue function:
void createQueue(struct pqueue *queue){
queue = malloc( sizeof(struct pqueue) );
queue->root = malloc(sizeof(struct node));
queue->root->next = 0;
queue->root->taskID = 12;
queue->root->priority = 5000;
}
I also try to add to the newly created queue like this:
void add(struct pqueue *queue, int taskID, int priority){
struct node *conductor;
conductor = queue->root;
if ( conductor != 0 ) {
while ( conductor->next != 0)
{
conductor = conductor->next;
}
}
conductor->next = malloc( sizeof(struct node) );
conductor = conductor->next;
if ( conductor == 0 )
{
printf( "Out of memory" );
}
/* initialize the new memory */
conductor->next = 0;
conductor->taskID = taskID;
conductor->priority = priority;
}
from the main function:
int main()
{
struct pqueue *queue;
createQueue(queue);
add(queue, 234093, 9332);
}
...but I keep segfaulting. Any reason why this keeps happening?
EDIT:
The structs for pqueue and node are like this:
struct node {
int taskID;
int priority;
struct node *next;
};
struct pqueue{
struct node *root;
};
In C, everything is passed by value. Therefore, when you call createQueue(queue), you are passing a copy of the pointer to the function. Then, inside the function, when you say queue = malloc(...), you are setting that copy of the pointer equal to your newly allocated memory - leaving main()'s copy of that pointer unchanged.
You want to do something like this:
void createQueue(struct pqueue **queue)
{
(*queue) = malloc( ... );
}
int main(void)
{
struct pqueue *queue;
createQueue(&queue);
}
This question has a more detailed description of what's going wrong for you.
I'm having trouble building a binary tree in C. I'm suppose to be able to add books to the tree where books with a later publishing year get added to the left and earlier publishing year gets added to the right. I keep getting a run error and i'm not really sure why.
#include <stdio.h>
#include <stdlib.h>
struct book {
char* name;
int year;
};
typedef struct tnode {
struct book *aBook;
struct tnode *left;
struct tnode *right;
} BTree;
BTree* addBook(BTree* nodeP, char* name, int year){
if( nodeP == NULL )
{
nodeP = (struct tnode*) malloc( sizeof( struct tnode ) );
(nodeP->aBook)->year = year;
(nodeP->aBook)->name = name;
/* initialize the children to null */
(nodeP)->left = NULL;
(nodeP)->right = NULL;
}
else if(year > (nodeP->aBook)->year)
{
addBook(&(nodeP)->left,name,year );
}
else if(year < (nodeP->aBook)->year)
{
addBook(&(nodeP)->right,name,year );
}
return nodeP;
}
void freeBTree(BTree* books)
{
if( books != NULL )
{
freeBTree(books->left);
freeBTree(books->right);
//free( books );
}
}
void printBooks(BTree* books){
if(books != NULL){
}
}
int main(int argc, char** argv) {
BTree *head;
head = addBook(head,"The C Programming Language", 1990);
/*addBook(head,"JavaScript, The Good Parts",2008);
addBook(head,"Accelerated C++: Practical Programming by Example", 2000);
addBook(head,"Scala for the impatient",2012);*/
}
You're trying to access an uninitalized pointer nodeP->aBook:
nodeP = (struct tnode*) malloc( sizeof( struct tnode ) );
(nodeP->aBook)->year = year;
You have to allocate space with malloc.
or, store the data directly in the node (with a struct, and not a pointer to a struct).
One problem is that you aren't initializing to NULL:
BTree *head;
should be
BTree *head = NULL;
I would recommend setting your compiler warnings higher. Your two recursive calls are not right and the compiler should have warned about them:
addBook(&(nodeP)->left,name,year );
should be:
addBook( nodeP->left,name,year );
from a parameter passing standpoint. However, this function won't work as it is right now since you are adding when the node pointer is NULL, which means you can't attach a parent to a child since the parent pointer node is gone. I think the logic should look at the applicable right/left node and if NULL, add right there in the routine, else call recursively till a node is found that has a NULL right/left pointer.
Something like this:
BTree *makeNode(char *name, int year)
{
// NOTE: 3 frees required for every node
BTree *nodeP = malloc( sizeof( struct tnode ) ); // 1
nodeP->aBook = malloc( sizeof(struct book) ); // 2
(nodeP->aBook)->year = year;
(nodeP->aBook)->name = malloc(strlen(name) + 1); // 3
strcpy((nodeP->aBook)->name,name);
/* initialize the children to null */
nodeP->left = NULL;
nodeP->right = NULL;
return nodeP;
}
BTree* addBook(BTree* nodeP, char* name, int year)
{
if ( nodeP == NULL )
{
nodeP = makeNode(name,year);
}
else if (year > (nodeP->aBook)->year)
{
if ( nodeP->left == NULL )
nodeP->left = makeNode(name,year);
else
addBook( nodeP->left,name,year );
}
else if(year < (nodeP->aBook)->year)
{
if ( nodeP->right == NULL )
nodeP->right = makeNode(name,year);
else
addBook( nodeP->right,name,year );
}
return nodeP;
}
void printBooks(BTree* books)
{
if (books != NULL) {
printf("book: %s %d\n",books->aBook->name,books->aBook->year);
printBooks(books->right);
printBooks(books->left);
}
}