My code is having segmentation fault (core dumped) here. I'm not pretty sure which line is causing it since I'm pretty new to C.
What I am trying to do here is to implement a binary search tree for each line on the file (only for insertion and search). Each line will not be more than 1000 words.
Here's my code:
BST *bst_ins(BST *bst, char *key, void *value)
{
BST* temp = NULL;
int cmp = strcmp(bst->kvp.key, key);
if(bst == NULL)
{ /* This for null node */
temp = (BST*)malloc(sizeof(BST)); /* allocate the memory of struct for new node */
temp->left = NULL;
temp->right = NULL;
temp->kvp.key = key;
temp->kvp.value = value;
}
else if(cmp < 0) /* Current node less than input */
{
bst->right = bst_ins(bst->right,key,value);
}
else if(cmp > 0)
{
bst->left = bst_ins(bst->left,key,value);
}
return bst;
}
KVP *bst_get(BST *bst, char *key)
{
KVP* return_this;
if(bst!=NULL)
{
if(bst->kvp.key==key)
{
return return_this;
}
else if(strcmp(bst->kvp.key, key) < 0) /* Current node less than input */
{
return bst_get(bst->left, key);
}
else if(strcmp(bst->kvp.key,key) > 0)
{
return bst_get(bst->right,key);
}
}
return 0;
}
Below is header.h
typedef struct {
char *key;
void *value;
} KVP;
typedef struct bst {
struct bst *left;
struct bst *right;
KVP kvp;
} BST;
Could someone please help me figure out which line is causing it?
Thanks.
EDIT:
SOLVED! FINALLY :D
Here's the main function.
int main()
{
char* str1=strdup("alokama");
char* str2=strdup("kokokoko");
BST *bst = NULL;
bst = bst_insert(bst,str1,NULL);
bst = bst_insert(bst,str2,NULL);
if(bst_get(bst,str1)){ printf ("yuhuu\n"); }
return 0;
}
When you call bst_ins, bst may be NULL, so you can't dereference it. Also, you define a temporary node, which is NULL. When you get to your string comparisons,
if (strcmp(temp->kvp.key, key) < 0) ...
you certainly dereference a NULL pointer. Not good. The code below fixes the issue and also calls strcmp only once per pass. Note how temp is defined only in the scope where a new node is created.
BST *bst_ins(BST * bst, char *key, void *value)
{
int cmp;
if (bst == NULL) {
BST *temp = (BST *) malloc(sizeof(*temp));
temp->left = NULL;
temp->right = NULL;
temp->kvp.key = key;
temp->kvp.value = value;
return temp;
}
cmp = strcmp(bst->kvp.key, key);
if (cmp < 0) {
bst->right = bst_ins(bst->right, key, value);
} else if (cmp > 0) {
bst->left = bst_ins(bst->left, key, value);
}
return bst;
}
You can now insert new nodes like so:
bst = bst_ins(bst, "plum", "1");
bst = bst_ins(bst, "apple", "2");
bst = bst_ins(bst, "orange", "3");
bst = bst_ins(bst, "kumquat", "4");
But that is a bit clumsy, because you have to assign the result to the root node, which is redundant and easy to forget. You also lose the useful possibility to return the (possibly new) node associated with the key.
A better approach might be to pass the address of the root node to functions that may change the tree. If you are not afraid of the (*bst) notation and the address-of poerator &, here goes:
BST *bst_ins(BST **bst, char *key, void *value)
{
int cmp;
if (*bst == NULL) {
*bst = (BST *) malloc(sizeof(**bst));
(*bst)->left = NULL;
(*bst)->right = NULL;
(*bst)->kvp.key = key;
(*bst)->kvp.value = value;
return *bst;
}
cmp = strcmp((*bst)->kvp.key, key);
if (cmp < 0) return bst_ins(&(*bst)->right, key, value);
if (cmp > 0) return bst_ins(&(*bst)->left, key, value);
return *bst;
}
and call it like so:
bst_ins(&bst, "plum", "1");
bst_ins(&bst, "apple", "2");
bst_ins(&bst, "orange", "3");
bst_ins(&bst, "kumquat", "4");
The function returns the node associated with the key, but you can easily ignore the return value.
Finally, make sure that your tree is properly deleted when you are done.
Related
I'm adding words (character per node) on a trie data structure - that happens correctly based on a implementantion I found on the web -
http://www.techiedelight.com/trie-implementation-insert-search-delete/
Although I want to extend this and add a list containing some data based on the words, such term frequency etc.
Right now I'm facing an issue with the pointer of the list when adding the first element on a trie node - in the method append_posting_list - and getting a segmetation fault.
Here is the code so far.
main.h
#ifndef TRIE_H
#define TRIE_H
#define CHAR_SIZE 26
typedef struct posting_list {
int doc_id;
int tf;
int df;
struct posting_list *next;
} posting_list_node ;
struct Trie
{
posting_list_node *p_node; // this will be the head of the posting list for every word;
int isLeaf; // 1 when node is a leaf node
struct Trie* character[CHAR_SIZE];
};
struct Trie* getNewTrieNode();
void insert(struct Trie* *head, char* str, int doc_id);
int search(struct Trie* head, char* str);
#endif //TRIE_H
main.c
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
int main(){
struct Trie* head = getNewTrieNode();
insert(&head, "hello", 1);
return 0;
}
// Function that returns a new Trie node
struct Trie* getNewTrieNode()
{
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
return node;
}
posting_list_node* get_mem(){
posting_list_node* p;
p = (posting_list_node *)malloc(sizeof(posting_list_node));
if (p == NULL){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
return p;
}
void append_posting_list(int doc_id, posting_list_node **n){
posting_list_node *new, *q;
new = get_mem();
new->doc_id = doc_id;
new->tf = 1;
new->next = NULL;
// if new is the first element of the list
if(n == NULL) {
*n = new;
} else {
q = *n;
while( q->next!=NULL) {
q = q->next;
}
q->next = new;
}
}
// Iterative function to insert a string in Trie.
void insert(struct Trie* *head, char* str, int doc_id)
{
// start from root node
struct Trie* curr = *head;
while (*str)
{
// create a new node if path doesn't exists
if (curr->character[*str - 'a'] == NULL)
curr->character[*str - 'a'] = getNewTrieNode();
// go to next node
curr = curr->character[*str - 'a'];
// move to next character
str++;
}
// already found this word, increase frequency
if(curr->isLeaf) {
curr->p_node->tf += 1;
} else {
append_posting_list(doc_id, curr->p_node);
// mark current node as leaf
curr->isLeaf = 1;
}
}
// Iterative function to search a string in Trie. It returns 1
// if the string is found in the Trie, else it returns 0
int search(struct Trie* head, char* str)
{
// return 0 if Trie is empty
if (head == NULL)
return 0;
struct Trie* curr = head;
while (*str)
{
// go to next node
curr = curr->character[*str - 'a'];
// if string is invalid (reached end of path in Trie)
if (curr == NULL)
return 0;
// move to next character
str++;
}
// if current node is a leaf and we have reached the
// end of the string, return 1
return curr->isLeaf;
}
I'm really stuck here.
Any suggestions would be really appreciated.
I found a couple things that when fixed, got rid of your segmentation fault.
In getNewTrieNode() I think you need to set p_node to NULL
struct Trie* getNewTrieNode() {
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
node->p_node = NULL;
return node;
}
append_posting_list() takes post_list_node **, but in insert(), you are passing just post_list_node *
void append_posting_list(int doc_id, posting_list_node **n)
append_posting_list(doc_id, curr->p_node);
looks like it should be
append_posting_list(doc_id, &(curr->p_node));
In append_posting_list()
if (n == NULL) {
should be
if (*n == NULL) {
in order to see if a pointer to an empty list is being passed in.
You should really have some functions to print out your data structure while you are working on it, so you can test each piece as you develop it. Simply compiling and running code and not getting any errors is no gurantee the code is working correctly with complex data structures like this. Making sure that each piece works perfectly before going on to the next piece will save you hours in trying to track down segmentation faults and other errors like this.
I am trying to print all the members of a linked list. I am traversing the list and counting the duplicate copies of the integers in the list if any. But when I traverse the list again to check for duplicate copies, my ipNext points to null terminating my previous traverse loop.
Inserting data function:
void insertIP(bstNode *head, char user[], int ip){
if(head != NULL){
bstNode* startList = head;
while ((startList) && (strcmp(startList->data, user) != 0) ){
if(strcmp(user, startList->data)<0)
{
startList=startList->left;
}
else if(strcmp(user, startList->data)>0)
{
startList=startList->left;
}
}
if (startList != NULL){
IP* new = (IP*)malloc(sizeof(IP));
new->ip = ip;
//new->count = (new->count + 1);
new->ipNext=NULL;
IP* temp = startList->ipHead;
startList->ipHead = new;
new->ipNext = temp;
}
}
}
Iteration function which looks for a specific data entry and count the occurences of it in the linked list if any.
bstNode* search(char* key, bstNode* root)
{
int res;
bstNode *leaf = root;
if( leaf != NULL ) {
res = strcmp(key, leaf->data);
if( res < 0)
search( key, leaf->left);
else if( res > 0)
search( key, leaf->right);
else
{
printf("\n'%s' found!\n", key);
//int count = 0;
bstNode *temp = leaf;
while (temp->ipHead != NULL) {
int tempip = temp->ipHead->ip;
int ipcount = 0;
uint32_t ip = tempip;
struct in_addr ip_addr;
ip_addr.s_addr = ip;
bstNode *cpy = leaf;
ipcount = count(&cpy, tempip);
//temp = leaf;
printf("The IP address is %s\n C:%d\n", inet_ntoa(ip_addr), ipcount);
temp->ipHead = temp->ipHead->ipNext;
}
}
}
else printf("\nNot in tree\n");
return leaf;
}
Supporting function (This set the ipNext value to null which terminates the loop in search. Even though I am passing a copy of the pointer, I think that is my problem).
int count(bstNode** start, int item)
{
bstNode* current = *start;
int count = 0;
while (current->ipHead->ipNext != NULL)
{
if (current->ipHead->ip == item)
{
count++;
}
current->ipHead = current->ipHead->ipNext;
}
return count;
}
The data structure decleration:
typedef struct ip{
int ip;
struct ip *ipNext;
}IP;
typedef struct bstNode
{
char data[32];
struct bstNode* left;
struct bstNode* right;
IP *ipHead;
}bstNode;
BST insert function:
bstNode *insert(bstNode *root, char *word, int ip)
{
bstNode *node = root;
if(node==NULL){
node= malloc(sizeof(bstNode));
//IP* ipNode=malloc(sizeof(IP));
strcpy(node->data, word);
node->left=NULL;
node->right=NULL;
insertIP(node, word, ip);
}
else{
if(strcmp(word, node->data)<0)
node->left=insert(node->left, word, ip);
else if(strcmp(word, node->data)>0)
node->right=insert(node->right, word,ip);
else if(strcmp(word, node->data) == 0) {
insertIP(node, word, ip);
}
}
return node;
}
I appreciate everyones help!
As pointed out in the comments, here is your problem:
while ((startList) && (strcmp(startList->data, user) != 0) ){
if(strcmp(user, startList->data)<0)
{
startList=startList->left;
}
else if(strcmp(user, startList->data)>0)
{
startList=startList->left;
}
}
You are taking the left path in both cases. I wouldn't post this as an answer (since it is already answered in the comments by Pras, but when I see this kind of non-optimized code, it bothers me: You may call the strcmp() function several times with the same data and the result will always be the same. strcmp() may be a costly operation if long strings are compared and besides you are doing this inside of a tree, so this operation could be performed A LOT of times. So why don't you assign the result in a variable the first time and then test the result, not call the strcmp() again. Like:
int result;
while (startList && (result = strcmp(startList->data, user)) ) {
if (result < 0)
{
startList = startList->left;
}
else if (result > 0)
{
startList = startList->right;
}
}
Actually the second if is not needed, you may use a simple else because the test for zero is done in the condition of the while statement, so apparently if the result is not < 0, it will be > 0 for sure.
I cannot figure out how to run this correctly, gives segmentation error. A piece of code is below. Can you look at head too , i am not sure if it is right way of initialising head to null in another file , it is run as follows :
Table tb ;
tb= initialise_table (table_size);
tb = insert(text_words,tb);
//these 3 typedef declarations are in a "some.h" file
typedef struct node * tree_ptr;
typedef char* Key_Type;
typedef struct table* Table;
struct node {
Key_Type element;
tree_ptr left;
tree_ptr right;
};
struct table {
tree_ptr head;
};
Table init_table() {
Table head = NULL;
}
Table insert(Key_Type key ,Table temp ) {
tree_ptr t = (tree_ptr)malloc(sizeof(tree_ptr));
t->element = key;
// t->left = t->right = NULL;
if (temp->head==NULL) {
temp = (Table)malloc (sizeof (Table));
temp->head = t;
printf("empty tree ");
}
else {
temp = insert(t->element,temp);
printf("inserted into ");
}
return temp;
printf("wowo!");
}
The primary issue is in the code which, you say, is used to invoke the functions:
Table tb;
tb = insert(text_words, tb);
You have an uninitialized pointer, tb, which you pass to the function. Inside the function, you have:
Table insert(Key_Type key, Table temp)
{
tree_ptr t = (tree_ptr)malloc(sizeof(*t)); // Fixed size
t->element = key;
// t->left = t->right = NULL;
if (temp->head==NULL)
{
You're therefore accessing (dereferencing) the undefined pointer, and your program is crashing.
You should, I assume, be initializing your table with table_init(), but that function is actually no help whatsoever. It defines and initializes a local variable, but doesn't return anything even though it promises to do so.
Please see Is it a good idea to typedef pointers? The short answer is 'No, it usually isn't a good idea'.
You still have problems even if you fix the calling code like this (a necessary but not sufficient step):
Table tb = NULL;
tb = insert(text_words, tb);
or maybe:
Table tb = init_table();
tb = insert(text_words, tb);
but you need a seriously upgraded version of init_table(), such as:
Table init_table(void)
{
Table root = malloc(sizeof(*head));
root->head = NULL;
return root;
}
Your code in insert() needs to ensure that it does not dereference a null pointer (instead of an indeterminate pointer).
Table insert(Key_Type key, Table root)
{
tree_ptr t = (tree_ptr)malloc(sizeof(*t)); // Fixed size
t->element = key;
t->left = t->right = NULL;
if (root == NULL)
{
root = init_table();
root->head = t;
}
else
{
…
}
return root;
}
Given the Key_Type is a char * in disguise, you may need to review how you save the keys in the tree structure; you may need to use strdup() to copy the data. It is impossible to say for sure without seeing how you are managing the strings that you pass to the insert() function. It could be OK to just save the pointer if the calling code ensures that a new pointer is passed each time. OTOH, if the same pointer is passed each time, you definitely need to copy the data, and using strdup() is a sensible way of doing that. Note that strdup() is standard on POSIX; it is not part of standard C.
Here's one major problem:
tree_ptr t = (tree_ptr) malloc(sizeof(tree_ptr));
should be:
tree_ptr t = (tree_ptr) malloc(sizeof(struct node));
Your code doesn't actually do any binary search. Indeed, it just infinitely recurses creating new nodes. Try something more like this:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct Node
{
char *element;
struct Node *left;
struct Node *right;
} Node;
typedef struct
{
Node *root;
size_t size;
} Tree;
void Tree_init(Tree *t);
Node *Tree_insert(Tree *t, const char *key);
void Tree_insert_r(Node *subtree, Node *n, size_t size);
void Tree_pre_order_r(Node *subtree);
void Tree_init(Tree *t)
{
t->root = NULL;
t->size = 0;
}
Node *Tree_insert(Tree *t, const char *key)
{
Node *ret = (Node*) malloc(sizeof(Node));
if (ret)
{
ret->left = ret->right = NULL;
if ((ret->element = strdup(key))) /* make a copy of key */
{
if (NULL != t->root)
Tree_insert_r(t->root, ret, t->size);
else
t->root = ret;
++t->size;
}
else
{
free(ret);
ret = NULL;
}
}
return ret;
}
void Tree_insert_r(Node *subtree, Node *n, size_t size)
{
int cmp = strcmp(n->element, subtree->element);
if (cmp < 0 || (cmp == 0 && size % 2 == 0))
{
if (NULL != subtree->left)
subtree = subtree->left;
else
{
subtree->left = n;
return;
}
}
else
{
if (NULL != subtree->right)
subtree = subtree->right;
else
{
subtree->right = n;
return;
}
}
Tree_insert_r(subtree, n, size);
}
void Tree_pre_order_r(Node *subtree)
{
if (NULL == subtree)
return;
fprintf(stdout, "'%s'\n", subtree->element);
Tree_pre_order_r(subtree->left);
Tree_pre_order_r(subtree->right);
}
int main()
{
Tree t;
Tree_init(&t);
Tree_insert(&t, "Hello");
Tree_insert(&t, "World!");
Tree_insert(&t, "etc.");
Tree_pre_order(t.root);
return 0;
}
I've been trying to get this BST working for the last few days, and I am getting stuck on the search function. The logic seems to be correct (unless I'm missing very important details) but there still is something wrong with the code. Could it be because I am dealing with strings? Anyways, here is some code:
EDIT: I've pinpointed somewhere that seems to be going wrong. It turns out that my root is always null. I placed a printf to test if the NULL-case were true, and it always printed true. I've added my tree initialization at the bottom of this question.
The (Updated) Search Function:
//Thank you, M Oehm
node* search(node * tree, char *key)
{
/* char *key is user input */
int cmp;
if(tree == NULL) {
return NULL;
}
cmp = strcmp(key, tree->key);
if(cmp < 0) return search(tree->left, key);
if(cmp > 0) return search(tree->right, key);
return tree;
}
Implementation in main function:
printf("Enter a string to search the tree with: ");
fgets(findNode, MAX_WORD, stdin);
findString = malloc(sizeof(char)*strlen(findNode)+1);
strcpy(findString,findNode);
printf("findString: %s\n", findString);
searched = search(&root, findString);
if(searched == NULL) {
printf("No_such_key\n");
free(findString);
}
else {
printNode(searched);
free(findString);
}
break;
Tree Initialization (via file parsing):
/* Loop through each line in the file*/
while(fgets(buffer, sizeof(buffer), file) != NULL) {
tempToken = strtok(buffer, " \n");
while(tempToken != NULL) {
/* Assign default values */
curr = (node *)malloc(sizeof(node));
curr->left = curr->right = NULL;
curr->key = malloc(sizeof(char)*strlen(tempToken)+1); /* +1 for '\0' */
strcpy(curr->key, tempToken);
curr->frequency = 1;
/* Insert node into tree */
insert(&root, curr);
/* Get next token */
tempToken = strtok(NULL, " \n");
}
}
/* Test insertion worked; close file */
print_inorder(root);
fclose(file);
Insertion Function:
void insert(node ** tree, node * item)
{
/* If no root, item is root */
if(!(*tree)) {
*tree = item;
return;
}
/* If item value is less than node in tree, assign to left */
if(strcmp(item->key,(*tree)->key) < 0) {
insert(&(*tree)->left, item);
}
else if(strcmp(item->key,(*tree)->key) > 0) {
insert(&(*tree)->right, item);
}
else if(strcmp(item->key,(*tree)->key) == 0) {
(*tree)->frequency++;
}
}
The print function shows me that the insertion works properly.
There are two errors in your code: You don't check whetehr the root node, to which you pass a pointer, is null and you don't return the results from the recursive functions.
Your function doesn't modify the tree, so you don't have to pass a pointer to the nodes. That method is useful for functions that modify the tree, e.g. for inserting or deleting nodes. Your function shoul pass a pointer to the root node. That also signals to the user that the tree won't be modified.
So here's a corrected version:
node* search(node *tree, const char *key)
{
int cmp;
if (tree == NULL) return NULL;
cmp = strcmp(key, tree->key);
if (cmp < 0) return search(tree->left, key);
if (cmp > 0) return search(tree->right, key);
return tree;
}
That version must be called like this:
node *hit = search(tree, "bingo!");
Note that this function does the string comparison only once and saves the result in a temporary variable. Your code calls strcmp up to three times.
You don't have to use recursion here. It's even a bit wasteful, because you have to percolate the answer up the first call. Recursion is useful when each step has to maintain a state, which you can represent as local variables. Here, you just change the input node.
Here's a non-recursive variant of the search function:
node* search(node *tree, const char *key)
{
while (tree) {
int cmp = strcmp(key, tree->key);
if (cmp == 0) return tree;
tree = (cmp < 0) ? tree->left : tree->right;
}
return NULL;
}
search(&(*tree)->left, key);
Should be:
return search(&(*tree)->left, key);
Same for the right case.
Try changing your function to something like this.
node* search(node * tree, char * key)
{
if(tree == NULL) {
return NULL;
}
if(strcmp(key,tree->key) < 0) {
return search(tree->left, key);
}
else if(strcmp(key,tree->key) > 0) {
return search(tree->right, key);
}
printf("Success!\n");
return tree;
}
A simple node* would suffice for your problem. No need for double pointers.
i am trying to write a program that will do the following
-read a file from std in
-read each line, and add each line to a binary tree
*if name is already in binary tree,dont add the name to the tree again but update its count of repititions
-print out the binary tree
the file being read in looks something like
dylan
bob
dylan
randall
randall
so when i print out the binary tree i would like it to print out
bob 1
dylan 2
randall 2
i was able to successfully print out the names without worrying about repetitions. I have commented out the blocks of code that mess my program up which is anything interacting with my search function that i added after the fact to take care of repetitions. The code builds a binary tree with each "leave" being a structure of 4 parts,the name,thecount,and the pointers to left and right childs.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char* name;
int count;
struct node* left;
struct node* right;
};
struct node* addNode(char* string);
void insert(struct node *root, char* stringgg);
void preorder(struct node *root);
int search(struct node* leaf,char* string2find);
int main()
{
char buffer[20];
struct node *root = NULL;
while( fgets(buffer, sizeof(buffer), stdin) != NULL )
{
if(root == NULL)
root = addNode(buffer);
else
insert(root,buffer);
}
preorder(root);
}
struct node* addNode(char* string)
{
struct node *temp = malloc(sizeof(struct node));
temp->name = malloc(strlen(string) + 1);
strcpy(temp->name,string);
temp->left = NULL;
temp->right = NULL;
return temp;
}
void insert(struct node *root, char* stringgg)
{
/* int flag = 5;
flag = search(root,stringgg);
if(flag == 1)
return; */
if(strcmp(stringgg,root->name) < 0)
{
if(root->left == NULL)
root->left = addNode(stringgg);
else
insert(root->left, stringgg);
}
else
{
if(root->right == NULL)
root->right = addNode(stringgg);
else
insert(root->right,stringgg);
}
}
/*int search(struct node* leaf,char* string2find)
{
if(strcmp(string2find,leaf->name) == 0)
{
leaf->count = leaf->count + 1;
return 1;
}
else if(strcmp(string2find,leaf->name) < 0)
{
return search(leaf->left,string2find);
}
else
{
return search(leaf->right,string2find);
}
return 0;
} */
void preorder(struct node *root)
{
if(root == NULL)
return;
printf("%s",root->name);
preorder(root->left);
preorder(root->right);
}
the above code prints out all the names even if there already in a tree. I was hoping that someone would be able to point out my search function errors so that it wont cause a segmentation fault when printing. Possible causes may be my inappropriate use of the return function in which i am trying to return to main if flag == 1 which means match was found so dont addnodes. but if flag does not equal 1 no match was found so go about adding nodes.
at main
while( fgets(buffer, sizeof(buffer), stdin) != NULL ){
char *p = strchr(buffer, '\n');
if(p) *p=0;//remove '\n'
at addNode
temp->count = 1;//initialize counter
return temp;
at insert
void insert(struct node *root, char* stringgg){
int cmp_stat = strcmp(stringgg,root->name);
if(cmp_stat == 0)
root->count++;
else if(cmp_stat < 0) {
if(root->left == NULL)
root->left = addNode(stringgg);
else
insert(root->left, stringgg);
} else {
if(root->right == NULL)
root->right = addNode(stringgg);
else
insert(root->right,stringgg);
}
}
at preorder
printf("%s %d\n",root->name, root->count);
The error is in searching for the very first item in the empty tree — you call
search(root, stringgg)
but root is NULL, so in search() you call
strcmp(string2find, leaf->name)
with leaf == NULL and the program crashes.
A cure: do not search BEFORE you update your tree, but rather search TO update it.
struct node* update(struct node* nd, const char* str)
{
int cmp;
// (sub)tree is empty? - create a new node with cnt==1
if(nd == NULL)
return CreateNode(str);
// test if the node found
cmp = strcmp(str, nd->name);
if(cmp == 0) // YES
nd->count ++; // update the counter
else if(cmp < 0) // NO - search in a subtree
nd->left = update(nd->left, str);
else
nd->right = update(nd->right, str);
return nd; // return the updated subtree
}
Then in main() you just update the tree and store it:
root = update(root, buffer);
Actually, the root value will change only once, on the first call, and all subsequent assignments will not change its value. However that makes the code much more readable.