Unable to iterate the linked list in C - c

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.

Related

counting occurrences of word in binary search tree

I'm working on creating a function word_count that counts the number of occurrences of the given word in a binary search. I'm having some trouble with how the logic would work, I'm stuck on the initial part. There's another function I created word_observe, that checks if a word is in the tree if it is not it adds it in and sets the count to one. If it is it increments count every time it comes across it. That could possibly be useful to understand the full program.
typedef struct tnode {
char *word;
int count;
struct tnode *left;
struct tnode *right;
} tnode;
tnode *word_observe(char *word, tnode *node) {
if (node != NULL) {
if (strcmp(node->word, word) == 0) {
node->count++;
return node;
} else if (strcmp(node->word, word) < 0) {
node->left = word_observe(word, node->left);
} else {
node->right = word_observe(word, node->right);
}
} else {
tnode *newnode = (tnode*)malloc(sizeof(tnode));
newnode->word = strdup(word);
newnode->count = 1;
newnode->left = NULL;
newnode->right = NULL;
node = newnode;
}
return node;
}
int word_count(char *word, tnode *node) {
if (node != NULL) {
if (strcmp(node->word, word) == 0) {
return node->count;
} else if (strcmp(word, node->word) < 0) {
word_count(word, node->left);
} else {
word_count(word, node->right);
}
}
return -1;
}
int main(void) {
tnode *counts = NULL;
counts = word_observe("dog", counts);
counts = word_observe("dog", counts);
counts = word_observe("apple", counts);
counts = word_observe("hello", counts);
counts = word_observe("pineapple", counts);
counts = word_observe("pineapple", counts);
counts = word_observe("pineapple", counts);
counts = word_observe("zebra", counts);
counts = word_observe("zebra", counts);
counts = word_observe("zebra", counts);
counts = word_observe("zebra", counts);
printf("apple: %d\n", word_count("apple", counts));
printf("dog: %d\n", word_count("dog", counts));
printf("pineapple: %d\n", word_count("pineapple", counts));
printf("zebra: %d\n", word_count("zebra", counts));
return 0;
}
You're kind of close. Your word_count function isn't searching correctly, which is puzzling since you are doing this correctly in word_observe. You need to search down the left side for < words and down the right side for > words. Since you're using recursion, you need to return those calls directly. When the word is found, simply return node->count, what you're doing invokes undefined behavior since count isn't initialized. Finally, you must return a value to indicate if the word isn't found.
int word_count(char *word, tnode *node) {
if (node != NULL) {
if (strcmp(node->word, word) == 0) {
// found the word, return its count. This value will
// ride the `return`s up the stack until it's returned back to main
return node->count;
} else if (strcmp(node->word, word) < 0) {
// < word, take the left path
return word_count(word, node->left);
} else {
// > word, take the right path
return word_count(word, node->right);
}
}
// couldn't find the word, return -1
return -1;
}
Working demo

Can't returning a tree node when is found

How can I return a tree node when I found it?
So, I have a binary tree and, when I search in the tree what I searched for was found I want to return the pointer to that node, so I can usa that node in other function. There is my search function:
Tnode *Tsearch(Tnode *r, char *word) {
if(r == NULL) {
printf("%s NOT FOUND\n", word);
return NULL;
}
int comp = strcasecmp(r->word, word);
if( comp == 0) {
printf("%s FOUND\n", r->word);
return r;
}
else if( comp > 0) {
Tsearch(r->left, word);
}
else if( comp < 0) {
Tsearch(r->right, word);
}
return 0;
}
My problem is that when I try to use the return of the function Tsearch it doesn't work and I really can't understand why and how to solve it.
The function where I want to use that returned node from the search function is the following:
int Tsearch_ref(Tnode *r, char (*words)[30]) {
if(r == NULL) {
return 0;
}
printf("%s, %d", words[0], (int)strlen(words[0]));
Tsearch(r,words[0]);
auxT = Tsearch(r,words[0]);
Lnode *aux = auxT->head;
printf("Title: %s\n", ((Book *)aux->ref)->title);
while(aux != NULL) {
aux_arr[i].ref=aux->ref;
printf("Title: %s\n", ((Book *)aux_arr[i].ref)->title);
printf("%p\n", &(aux_arr[i].ref));
aux = aux->next;
i++;
}
}
This function is not complete because I was trying to solve the return problem, but basically I want to take that tree node that have a list inside and put that list into a temporary array.
The structures are the following:
typedef struct {
char *title;
char isbn13[ISBN13_SIZE];
char *authors;
char *publisher;
int year;
} Book;
typedef struct lnode {
struct lnode *next;
void *ref;
} Lnode;
typedef struct tnode {
struct tnode *left;
struct tnode *right;
char *word;
Lnode *head;
} Tnode;
It's my first question here in StackOverflow, so if you need any more info about anything I will obviously provide it.
Thanks in advance!
You need to change the recursive calls to Tsearch to actually return the found node. So, instead of this code:
else if( comp > 0) {
Tsearch(r->left, word);
}
else if( comp < 0) {
Tsearch(r->right, word);
}
do this:
else if( comp > 0) {
return Tsearch(r->left, word);
}
else if( comp < 0) {
return Tsearch(r->right, word);
}
Note that if your tree is very deep, you may use up the entire call stack and throw an exception.
Why not use while loop?
Tnode *Tsearch(Tnode *r, char *word) {
Tnode *cur = r;
int comp;
while (cur != NULL)
{
if ((comp = strcasecmp(cur->word, word)) == 0)
{
printf("%s FOUND\n", cur->word);
return cur;
}
else if (comp > 0)
{
/* Move to the left child */
cur = cur->left;
}
else
{
/* Move to the right child */
cur = cur->right;
}
}
printf("NOT FOUND\n");
return NULL;
}

How to insert data in linked structure

My insertion worked, so a new question, How do I set a data to NULL in C? Pls see the last part for illustration.!
I have defined a structure type
typedef struct node {
char* data;
int weight;
bool end_of_key;
struct node * left;
struct node * equal;
struct node * right;
} node_t;
int main(int argc, char *argv[]){
node_t* root=NULL;
int weight;
int i = 1;
insert(root,"cat",3);
insert(root,"at",2);
insert(root,"cute",4);
.....
return 0 ;}
This is my insert function
node_t* insert(node_t* pNode,char* word, int weight) {
/**
* Create a new pNode, and save a character from word
*/
pNode = (node_t*)malloc(sizeof(node_t));
if(*pNode->data == NULL){
pNode->left = NULL;
pNode->equal = NULL;
pNode->right = NULL;
pNode->data = word;
}
if (word[0] < *(pNode->data)) {
/**
* Insert the character on the left branch
*/
pNode->left = insert(pNode, word, weight);
}
else if (word[0] == *(pNode->data)) {
if ((word[1]) == '\0') {
/**
*set pNode end_of_key_flag to true and assign weight
*/
pNode->end_of_key = true;
pNode->weight = weight;
// printf("%c", *(pNode->data++));
}
else {
/**
* If the word contains more characters, try to insert them
* under the equal branch
*/
// printf("%c", *(pNode->data++));
pNode->equal = insert(pNode,word + 1, weight);
}
}
else {
/**
* If current char in word is greater than char in pData
* Insert the character on the right branch
*/
pNode->right = insert(pNode,word, weight);
}
return pNode;}
this code is trying to do this
So my insertion finally worked but it appears that it can only insert one thing,I am wondering how do I set data to NULL in C?
if(*pNode->data == NULL){
pNode->left = NULL;
pNode->equal = NULL;
pNode->right = NULL;
pNode->data = word;
}
I want to run this four lines of code when *pNode->data is empty but it apparently did not work the way I wanted it to.
Some improvements of your code
insert() must have first parameter to be node_t ** (see comments)
char *data must be char data, because every node contains only one char
weight can be calculated when the list is filled up
Here is corrected version of your code. Function get() is used to find the key in the filled up list (for testing).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct node {
char data;
int weight;
struct node * left;
struct node * equal;
struct node * right;
} node_t;
void insert(node_t** pNode, char* word, int weight)
{
char data;
node_t **pNext;
node_t *pCurrent;
if (word == NULL)
{
return ;
}
data = word[weight];
if (*pNode == NULL)
{
*pNode = malloc(sizeof(node_t));
pCurrent = *pNode;
memset(pCurrent, 0, sizeof(node_t));
pCurrent->data = data;
}
else
{
pCurrent = *pNode;
}
if (data == pCurrent->data)
{
weight ++;
if (strlen(word) == weight)
{
pCurrent->weight = weight;
return;
}
pNext = &pCurrent->equal;
}
else if (data > pCurrent->data)
{
pNext = &pCurrent->right;
}
else
{
pNext = &pCurrent->left;
}
insert(pNext, word, weight);
}
int get(node_t** pNode, char *word, int weight)
{
char data;
node_t **pNext;
node_t *pCurrent;
if (word == NULL)
{
return 0;
}
data = word[weight];
if (*pNode == NULL)
{
return 0; // not found
}
pCurrent = *pNode;
if (data == pCurrent->data)
{
weight ++;
if (strlen(word) == weight)
{
return pCurrent->weight;
}
pNext = &pCurrent->equal;
}
else if (data > pCurrent->data)
{
pNext = &pCurrent->right;
}
else
{
pNext = &pCurrent->left;
}
return get(pNext, word, weight);
}
int main()
{
node_t * root = NULL;
insert(&root, "cat", 0);
insert(&root, "at", 0);
insert(&root, "cute", 0);
printf("cat=%d\n",get(&root,"cat",0)); // cat=3
printf("at=%d\n",get(&root,"at",0)); // at=2
printf("cute=%d\n",get(&root,"cute",0)); // cute=4
// todo: free memory
return 0;
}
The code is tested except freeing the memory.
First, there is something wrong with your insert() signature
(as already pointed by #MichaelWalz )
you'd rather
node_t* insert(node_t** pNode, char* word, int weight);
and then
insert(&root,"cute",4);
why don't you start fixing this and edit your post ?

Segmentation Fault (Core Dumped) when implementing binary tree

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.

Binary Tree segmentation fault after implementing search function

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.

Resources