As an exercise I am trying to work on a Binary search tree!
I have created the code and it seems to run, but when I try to add a customer it crashes. After debugging the code I get a segmentation fault in line 82, where I try to allocate memory to root... Researching for a while I see that it is something related to memory, but can't figure what is going on with my code... Any suggestions about what is causing this failure when trying to allocate memory?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING 50
void flush();
struct customer {
char *name;
char *address;
char *email;
};
struct double_linked_list {
struct customer *data;
struct double_linked_list *previous;
struct double_linked_list *next;
};
struct double_linked_list *customers_head = 0;
struct BST_node {
struct double_linked_list *data;
struct BST_node *left;
struct BST_node *right;
};
struct BST_node *BST_email_root = 0;
struct BST_node *BST_find_customer(struct BST_node *root, char *email) {
if (root == NULL)
return NULL;
if (strcmp(email, root->data->data->email) == 0)
return root;
else {
if (strcmp(email, root->data->data->email) == -1)
return BST_find_customer(root->left, email);
else
return BST_find_customer(root->right, email);
}
}
void find_customer() {
char email[MAX_STRING];
struct double_linked_list *l;
struct BST_node *b;
printf("Give the email of the customer (up to %d characters) : ", MAX_STRING - 1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b == 0)
printf("There is no customer with this email.\n");
else {
l = b->data;
printf("Customer found! \n");
printf("Name : %s\n", l->data->name);
printf("Address : %s\n", l->data->address);
printf("Email : %s\n", l->data->email);
}
}
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL);
{
root = (struct BST_node *)malloc(sizeof(struct BST_node));
if (root == NULL) {
printf("Out of Memory!");
exit(1);
}
root->data = l;
root->left = NULL;
root->right = NULL;
}
if (strcmp(l->data->email, root->data->data->email) == -1)
root->left = new_BST_node(root->left, l);
else
root->right = new_BST_node(root->right, l);
return root;
};
struct double_linked_list *new_customer() {
char name[MAX_STRING], address[MAX_STRING], email[MAX_STRING];
struct BST_node *b;
struct double_linked_list *l;
struct customer *c;
printf("\nADDING NEW CUSTOMER\n=\n\n");
printf("Give name (up to %d characters): ", MAX_STRING - 1);
gets(name);
printf("Give address (up to %d characters): ", MAX_STRING - 1);
gets(address);
printf("Give email (up to %d characters): ", MAX_STRING - 1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b) {
printf("Duplicate email. Customer aborted.\n");
return 0;
}
c = (struct customer *)malloc(sizeof(struct customer));
if (c == 0) {
printf("Not enough memory.\n");
return 0;
}
c->name = strdup(name); // check for memory allocation problem
if (c->name == 0)
return 0;
c->address = strdup(address); // check for memory allocation problem
if (c->address == 0)
return 0;
c->email = strdup(email); // check for memory allocation problem
if (c->email == 0)
return 0;
l = (struct double_linked_list*)malloc(sizeof(struct double_linked_list));
if (l == 0) {
printf("Not enough memory.\n");
free(c->name);
free(c->address);
free(c->email);
free(c);
return 0;
}
l->data = c;
l->previous = 0;
l->next = customers_head;
if (customers_head)
customers_head->previous = l;
customers_head = l;
BST_email_root = new_BST_node(BST_email_root, l);
return l;
}
void displaymenu() {
printf("\n\n");
printf("1. New customer\n");
printf("2. Find customer using email\n");
printf("0. Exit\n\n");
printf("Give a choice (0-6) : ");
}
void flush() {
char ch;
while ((ch = getchar()) != '\n' && ch != EOF);
}
int main() {
int choice;
do {
displaymenu();
scanf("%d", &choice);
flush();
switch (choice) {
case 1:
new_customer();
break;
case 2:
find_customer();
break;
}
} while (choice != 0);
return 0;
}
Codeblocks debugger gives the following information
Active debugger config: GDB/CDB debugger:Default
Building to ensure sources are up-to-date
Selecting target:
Debug
Adding source dir: C:\debug\
Adding source dir: C:\debug\
Adding file: C:\debug\bin\Debug\debug.exe
Changing directory to: C:/debug/.
Set variable: PATH=.;C:\Program Files\CodeBlocks\MinGW\bin;C:\Program Files\CodeBlocks\MinGW;C:\Windows\System32;C:\Windows;C:\Windows\System32\wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Program Files\ATI Technologies\ATI.ACE\Core-Static;C:\Users\baskon\AppData\Local\Microsoft\WindowsApps
Starting debugger: C:\Program Files\CodeBlocks\MINGW\bin\gdb.exe -nx -fullname -quiet -args C:/debug/bin/Debug/debug.exe
done
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
Debugger name and version: GNU gdb (GDB) 7.6.1
Child process PID: 5908
Program received signal SIGSEGV, Segmentation fault.
In ?? () ()
9 0x00401480 in new_BST_node (root=0x0, l=0xbe0ec8) at C:\debug\main.c:82
C:\debug\main.c:82:1907:beg:0x401480
At C:\debug\main.c:82
9 0x00401480 in new_BST_node (root=0x0, l=0xbe0ec8) at C:\debug\main.c:82
C:\debug\main.c:82:1907:beg:0x401480
The call stack is the following
There are multiple problems in your code:
You have a classic bug here:
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL);
{
root = (struct BST_node *)malloc(sizeof(struct BST_node));
The ; at the end of the if statement line is parsed as an empty statement. The subsequent block, introduced by the { will always be executed.
You can avoid this kind of silly bug by always using braces for your compound statements and placing them on the same line as the beginning of the statement, not on the next line. This is close to the original K&R style used by the creators of the C language more than 40 years ago.
The type for variable ch in function flush should be int to allow proper distinction of all values returned by getc(): all values of unsigned char plus the special value EOF:
void flush(void) {
int ch;
while ((ch = getchar()) != EOF && ch != '\n') {
continue;
}
}
Note that you should make the empty statement more explicit as I did above, to avoid confusion and bugs such as the previous one.
You should not use the obsolete unsafe function gets(): Use fgets() and strip the trailing newline with strcspn().
When comparing strings with strcmp(), you should only rely on the sign of the return value. In functions BST_find_customer() and new_BST_node(), you compare with -1: this is unreliable. Use if (strcmp(email, root->data->data->email) < 0) instead.
In function new_BST_node(), You do not return root when you create a new node in the tree. Here is a corrected version:
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l) {
if (root == NULL) {
root = malloc(sizeof(*root));
if (root == NULL) {
printf("Out of Memory!");
exit(1);
}
root->data = l;
root->left = NULL;
root->right = NULL;
return root;
}
if (strcmp(l->data->email, root->data->data->email) < 0) {
root->left = new_BST_node(root->left, l);
} else {
root->right = new_BST_node(root->right, l);
}
return root;
}
Note that this is causing your bug as you probably have an infinite recursion here.
Finally a couple pieces of advice:
use NULL instead of 0 when comparing pointers to the null pointer. It is more readable.
avoid naming a variable l as this name is graphically too close to 1 with the fixed pitch fonts used in programming environments. Sometimes it is almost indistinguishable.
Ok, so after testing everything i found out what is wrong however i can't figure out why.. Any Suggestions??
I think that strcmp returns values of either 0 or -1 or 1.
But there was the problem, if i didn't define exactly if strcmp ==1 or if strcmp ==-1 ...i had an infinite loop as it seems (i used a printf command to see what is going on, and i discovered the bug..)
By changing
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l)
{
if (root==NULL)
{
root = (struct BST_node *) malloc (sizeof(struct BST_node ));
if (root==NULL)
{
printf("Out of Memory!");
exit(1);
}
root->data=l;
root->left=NULL;
root->right=NULL;
}
if (strcmp(l->data->email, root->data->data->email) == -1)
root->left =new_BST_node(root->left,l);
else
root->right =new_BST_node(root->right,l);
return root;
};
to
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l)
{
if (root==NULL)
{
root= (struct BST_node *)malloc(sizeof(struct BST_node ));
if (root==NULL)
{
printf("Out of Memory!");
exit(1);
}
root->data=l;
root->left=NULL;
root->right=NULL;
}
if ((strcmp(l->data->email, root->data->data->email))==-1)
root->left =new_BST_node(root->left,l);
else if ((strcmp(l->data->email, root->data->data->email)) ==1)
root->right =new_BST_node(root->right,l);
return root;
};
everything works fine..
But why didnt the other code work? I am pretty sure it is the same...
Related
This is my algorithm for adding nodes to a linked list which is in a sorted way for surnames of persons.
Here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct Node {
char Name[1024];
char Surname[1024];
char Telno[1024];
struct Node* next;
};
void Add(struct Node** firstnode, struct Node* NewNode)
{
struct Node* tempo;
//printf("%d",strcmp((*firstnode)->Surname,NewNode->Surname));
if (*firstnode == NULL || (strcmp((*firstnode)->Surname,NewNode->Surname) > 0)) {
NewNode->next = *firstnode;
*firstnode = NewNode;
}
else {
tempo = *firstnode;
while (tempo->next != NULL && strcmp(tempo->Surname,NewNode->Surname) < 0) {
tempo = tempo->next;
}
NewNode->next = tempo->next;
tempo->next = NewNode;
}
}
struct Node* CreateNode(char name[1024], char surname[1024], char telno[1024])
{
struct Node* NewNode = (struct Node*)malloc(sizeof(struct Node));
strcpy(NewNode->Name,name);
strcpy(NewNode->Surname,surname);
strcpy(NewNode->Telno,telno);
NewNode->next = NULL;
return NewNode;
}
void Printlinkedlist(struct Node* head)
{
struct Node* temp = head;
while (temp != NULL) {
printf("%s %s %s\n", temp->Name,temp->Surname,temp->Telno);
temp = temp->next;
}
}
struct Node* head = NULL;
struct Node* temp;
int main()
{
int personcount;
char name[1024],surname[1024],telno[1024];
printf("Please give the count of person:");
scanf("%d", &personcount);
for (int i = 0; i < personcount; i++) {
printf("Please give the name of %d. person:", i + 1);
scanf(" %s", &name);
printf("Please give the surname of %d. person:", i + 1);
scanf(" %s", &surname);
printf("Please give the phone number of %d. person:", i + 1);
scanf(" %s", &telno);
temp = CreateNode(name,surname,telno);
Add(&head, temp);
}
printf("\n -------------- Linkedlist --------------\n");
Printlinkedlist(head);
return 0;
}
The first problem is this: For example, if I enter people's surnames as G, A, L, E, K (So first person's last name will be "G", second person's last name will be "A" etc..), it gives an incorrectly ordered output.
And the second one is: If I delete the comment line characters behind the printf inside the add function, I get a segmentation fault that I don't understand why
Thanks for the answer.
It should first be said that you could, and should, have figured it out yourself by either:
Debugging the program:
On Linux: How Can I debug a C program on Linux?
On Windows: How do you debug a C program on Windows?
Enabling core dumps and analyzing the core file you get when your program crashes; see this explanation.
But, more to the point, let's have a look at (some of) your code:
if (*firstnode == NULL || /* another condition */) {
// do stuff
}
else {
// so *firstnode may be NULL here
tempo = *firstnode;
while (tempo->next != /* some value */ && /* another condition*/ ) {
// do stuff
}
// do stuff
}
See the problem? tempo could get assigned a NULL point, and then de-referenced to get to the next field. That would likely cause a segmentation fault.
I'm working on an assignment that can accept commands from keyboard to insert people into a hashtable. After someone is inserted into the hastable, they can be "friended" with another person in the table. The way I have to store who is friends with who is a binary search tree. What I have to do is for the hashtable the first part of the node would be the person's name, then then next is a pointer to the bst for that person's friends, and finally the end is a pointer to the next node for chaining if there is a collision. Here is a visual example...
I have been able to insert people into my table, but the problem that I can not figure out is how to access the BST and add in friends for that person. Here is my code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Structures
struct linkedList{
char *name;
struct linkedList *next;
struct linkedList *tree;
};
typedef struct linkedList list;
struct hashTable{
int size;
list **table;
};
typedef struct hashTable hash;
struct bst{
char *val;
struct bst *l;
struct bst *r;
};
int main(){
char input[50];
char *ch, cmd_str[50], name[30];
// Make hash table for names
hash *profiles;
profiles = createHashTable(1001);
while(1){
// Get keyboard input
fgets(input, 50, stdin);
input[strlen(input)-1] = '\0';
// parse the input
ch = strtok(input, " ");
strcpy(cmd_str,ch);
if(strcmp("CREATE", cmd_str) == 0){
ch = strtok(NULL, " \n");
insertPerson(profiles, ch);
}
else if(strcmp("FRIEND", cmd_str) == 0){
ch = strtok(NULL, " \n");
strcpy(name, ch);
ch = strtok(NULL, " \n");
friendPerson(profiles, name, ch);
}
else if(strcmp("UNFRIEND", cmd_str) == 0){
ch = strtok(NULL, " \n");
}
else if(strcmp("LIST", cmd_str) == 0){
ch = strtok(NULL, " \n");
printFriends(profiles, ch);
}
else if(strcmp("QUERY", cmd_str) == 0){
}
else if(strcmp("BIGGEST-FRIEND-CIRCLE", cmd_str) == 0){
}
else if(strcmp("INFLUENTIAL-FRIEND", cmd_str) == 0){
}
else if(strcmp("EXIT", cmd_str) == 0){
printf("\nExiting...\n");
return 0;
}
else{
printf("\nBad Command.\n");
}
}
}
// Creates Hash Table
hash *createHashTable(int size){
int i;
hash *new_table;
if((new_table = malloc(sizeof(hash))) == NULL)
return NULL;
if((new_table->table = malloc(sizeof(list *) * size)) == NULL)
return NULL;
for(i=0; i < size; i++)
new_table->table[i] = NULL;
new_table->size = size;
return new_table;
}
// hashing function
int keyHash(char *name){
int c;
unsigned long key;
while(c = *name++)
key = ((key<<5) + key) + c;
return key%1000;
}
// insert a person into the hash table
void insertPerson(hash *profiles, char *name){
struct linkedList *item = (struct linkedList*)malloc(sizeof(struct linkedList));
int hash_val = keyHash(name);
item->name = name;
item->next = NULL;
item->tree = new_tree;
// Collision case
if(profiles->table[hash_val] != NULL){
while(profiles->table[hash_val]->next != NULL){
profiles->table[hash_val] = profiles->table[hash_val]->next;
}
profiles->table[hash_val]->next = item;
}
// Empty cell
else{
profiles->table[hash_val] = item;
}
}
// friend two people inside the hash table
void friendPerson(hash *profiles, char *name, char *_friend){
int hash1 = keyHash(name);
int hash2 = keyHash(_friend);
// check if the names are already in system
if(!profiles->table[hash1]){
printf("%s is not yet in the system", name);
return;
}
if(!profiles->table[hash2]){
printf("%s is not yet in the system", _friend);
return;
}
// add first friend
if(strcmp(profiles->table[hash1]->name, name) == 0){
insertBST(profiles->table[hash1]->tree, _friend);
}
else{
while(profiles->table[hash1]->next != NULL){
if(strcmp(profiles->table[hash1]->name, name) == 0)){
break;
}
profiles->table[hash1] = profiles->table[hash1]->next;
}
insertBST(profiles->table[hash1]->tree, _friend);
}
// add second friend
if(strcmp(profiles->table[hash2]->name, _friend) == 0){
insertBST(profiles->table[hash2]->tree, name);
}
else{
while(profiles->table[hash2]->next != NULL){
if(strcmp(profiles->table[hash2]->name, name) == 0)){
break;
}
profiles->table[hash2] = profiles->table[hash1]->next;
}
insertBST(profiles->table[hash2]->tree, name);
}
}
// creates a new bst node
struct bst *newBSTNode(char *name){
struct bst *temp = (struct bst* )malloc(sizeof(struct bst));
temp->val = strdup(name);
strcpy(temp->val, name);
temp->l = temp->r = NULL;
return temp;
}
// Inserts the a friend into a BST
struct bst *insertBST(struct bst *node, char *name){
if(!node)
return newBSTNode(name);
else{
if(strcmp(name, node->val) < 0){
node->l = insertBST(node->l, name);
}
else if(strcmp(name, node->val) > 0){
node->r = insertBST(node->r, name);
}
}
return node;
}
// Inorder print of names
void inorder(struct bst *root){
if(!root){
inorder(root->l);
printf("%s ", root->val);
inorder(root->r);
}
}
// Sends to function to print names
void printFriends(hash *profiles, char *name){
int hash_val = keyHash(name);
inorder(profiles->table[hash_val]->tree);
}
How would I be able to access the BST of said person? The struct bst *tree = profiles->table[hash1]->tree; was my previous attempt, but it was more of a shot in the dark. Thanks in advance!
Update: Okay, so I have been able to add friends (I think) and now I'm trying to print them with void printFriends(). However when I run the function nothing prints out. Would anyone know where I'm messing it up? I've updated the code above.
Your linkedList stores the name and a tree pointer. But the type of tree is linkedList. Change that to struct bst *. You'll have to reorder the declarations, or insert a forward declaration.
Implement a search. You check if the hash buckets are empty, but you don't search for the matching name.
Once you find a matching name in the bucket, the same node contains the aforementioned tree pointer. Insert the friend in the tree. Depending on your logic, you may or may not want to insert a backreference in the other person's tree. (If Alice is friends with Bob, does that make Bob friends with Alice automatically? Or wait for confirmation?)
I am working on an algorithm to delete a node with a given key from a binary search tree. So far, I have been able to come up with the following code:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
typedef int ElType;
typedef struct Tree {
ElType key;
struct Tree *left;
struct Tree *right;
struct Tree *parent;
} Tree;
Tree* InsertBST(Tree* t, int k)
{
if (t == NULL) {
Tree* w = (Tree*) malloc(sizeof(Tree));
w->key = k;
w->left = NULL;
w->right = NULL;
w->parent = NULL;
return w;
}
if (k <= t->key) {
t->left = InsertBST(t->left, k);
t->left->parent = t;
}
else {
t->right = InsertBST(t->right, k);
t->right->parent = t;
}
return t;
}
Tree* DeleteMaxOfBST(Tree* t, ElType *deleted_value)
{
if (t == NULL) {
*deleted_value = -1;
return NULL;
}
if (t->right == NULL) {
*deleted_value = t->key;
Tree* w = t->left;
w->parent = t->parent;
free(t);
return w;
}
t->right = DeleteMaxOfBST(t->right, deleted_value);
return t;
}
Tree* DeleteNodeOfBST(Tree* t, int k)
{
if (t == NULL) return NULL;
if (k < t->key) {
t->left = DeleteNodeOfBST(t->left, k);
return t;
}
else if (k > t->key) {
t->right = DeleteNodeOfBST(t->right, k);
return t;
}
else if (t->left == NULL) {
Tree* w = t->right;
w->parent = t->parent;
free(t);
return w;
}
else {
ElType max_left;
t->left = DeleteMaxOfBST(t->left, &max_left);
t->key = max_left;
return t;
}
}
The general idea is that I want to work with a BST with pointers to parent nodes and be able to delete a node with whichever key I specify while preserving the structure of a BST.
My code works for some keys in some trees but crashes for other keys without any apparent pattern. I then get the following error:
Segmentation fault (core dumped)
I am inclined to think I have messed up the pointers to the parent nodes but cannot quite pinpoint where the fault is. I am relatively new to C, so I would appreciate any comments whether pointers are in fact the problem here and how to possibly fix this.
So, without any examples of how your code runs it's hard to say where exactly the segmentation fault is occurring when your program is running. When your program encounters a segmentation fault that means that the program is attempting to access memory that, for whatever reason, it is unable to. This generally means your pointers are trying to point at an address in memory that they shouldn't be.
My suggestion would be to run the code step by step and see where the problem occurs. Or find a debugger that can show you the memory issues your program is having. I know that the program Valgrind exists for Ubuntu and other Linux best machines, but I'm not sure what others are available for other OSes. You can read more about Valgrind here: http://valgrind.org/. I use it whenever I need to check for potential memory handling issues in my programs.
Other than that, just keep a real close eye on the space that you create using malloc, as well as where your pointers are pointing. Make sure to reconnect your tree properly when you delete the given node. Manually handling memory can be a pain, but you'll get the hang of it.
Here is the source code for C Program for Insertion and Deletion in Binary Search Tree Recursive..................
/* C Program for Insertion and Deletion in Binary Search Tree Recursive */
#include<stdio.h>
#include<stdlib.h>
struct node
{
struct node *lchild;
int info;
struct node *rchild;
};
struct node *insert(struct node *ptr, int ikey);
void display(struct node *ptr,int level);
struct node *del(struct node *ptr, int dkey);
int main( )
{
struct node *root=NULL,*ptr;
int choice,k;
while(1)
{
printf("\n");
printf("1.Insert\n");
printf("2.Delete\n");
printf("3.Display\n");
printf("4.Quit\n");
printf("\nEnter your choice : ");
scanf("%d",&choice);
switch(choice)
{
case 1:
printf("Enter the key to be inserted : ");
scanf("%d",&k);
root = insert(root, k);
break;
case 2:
printf("Enter the key to be deleted : ");
scanf("%d",&k);
root = del(root,k);
break;
case 3:
display(root,0);
break;
case 4:
exit(1);
default:
printf("\nWrong choice\n");
}/*End of switch */
}/*End of while */
return 0;
}/*End of main( )*/
struct node *insert(struct node *ptr, int ikey )
{
if(ptr==NULL)
{
ptr = (struct node *) malloc(sizeof(struct node));
ptr->info = ikey;
ptr->lchild = NULL;
ptr->rchild = NULL;
}
else if(ikey < ptr->info) /*Insertion in left subtree*/
ptr->lchild = insert(ptr->lchild, ikey);
else if(ikey > ptr->info) /*Insertion in right subtree */
ptr->rchild = insert(ptr->rchild, ikey);
else
printf("\nDuplicate key\n");
return ptr;
}/*End of insert( )*/
void display(struct node *ptr,int level)
{
int i;
if(ptr == NULL )/*Base Case*/
return;
else
{
display(ptr->rchild, level+1);
printf("\n");
for (i=0; i<level; i++)
printf(" ");
printf("%d", ptr->info);
display(ptr->lchild, level+1);
}
printf("\n");
}/*End of display()*/
struct node *del(struct node *ptr, int dkey)
{
struct node *tmp, *succ;
if( ptr == NULL)
{
printf("dkey not found\n");
return(ptr);
}
if( dkey < ptr->info )/*delete from left subtree*/
ptr->lchild = del(ptr->lchild, dkey);
else if( dkey > ptr->info )/*delete from right subtree*/
ptr->rchild = del(ptr->rchild, dkey);
else
{
/*key to be deleted is found*/
if( ptr->lchild!=NULL && ptr->rchild!=NULL ) /*2 children*/
{
succ=ptr->rchild;
while(succ->lchild)
succ=succ->lchild;
ptr->info=succ->info;
ptr->rchild = del(ptr->rchild, succ->info);
}
else
{
tmp = ptr;
if( ptr->lchild != NULL ) /*only left child*/
ptr = ptr->lchild;
else if( ptr->rchild != NULL) /*only right child*/
ptr = ptr->rchild;
else /* no child */
ptr = NULL;
free(tmp);
}
}
return ptr;
}/*End of del( )*/
Hope it may help you. For more details, Visit here for More Operations on Binary Search tree ---> C Program for Insertion and Deletion in Binary Search Tree Recursive
and C Program for binary search tree deletion without recursion
I am working on a program that uses a binary search tree (as an exercise).
My problem is that when I try to add a customer(in the middle of my code lines 65-69) I get an error that BS_node is undeclared, though I insert struct BST_node *root in this function..
Part of my code is below, just for the readers to read it easier, if requested I can upload the full code ! Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING 50
void flush();
struct customer {
char *name;
char *address;
char *email;
};
struct double_linked_list {
struct customer *data;
struct double_linked_list *previous;
struct double_linked_list *next;
};
struct double_linked_list *customers_head=0;
struct BST_node {
struct double_linked_list *data;
struct BST_node *left;
struct BST_node *right;
};
struct BST_node *BST_email_root = 0;
struct BST_node *BST_find_customer(struct BST_node *root, char *email) {
if (root==NULL)
return NULL;
if (strcmp(email,root->data->data->email)==0)
return root;
else
{
if (strcmp(email,root->data->data->email)==-1)
return BST_find_customer(root->left,email);
else
return BST_find_customer(root->right,email);
}
}
void find_customer() {
char email[MAX_STRING];
struct double_linked_list *l;
struct BST_node *b;
printf("Give the email of the customer (up to %d characters) : ", MAX_STRING-1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b==0)
printf("There is no customer with this email.\n");
else
{
l = b->data;
printf("Customer found! \n");
printf("Name : %s\n", l->data->name);
printf("Address : %s\n", l->data->address);
printf("Email : %s\n", l->data->email);
}
}
struct BST_node *new_BST_node(struct BST_node *root, struct double_linked_list *l)
{
if (root==NULL);
{
root = (BST_node *) malloc (sizeof(BST_node ));
if (root==NULL)
{
printf("Out of Memory!");
exit(1);
}
root->data=l;
root->left=NULL;
root->right=NULL;
}
if (strcmp(l->data->email,root->data->data->email)==-1)
root->left =new_BST_node(root->left,l);
else root->right =new_BST_node(root->right,l);
return root;
};
struct double_linked_list *new_customer()
{
char name[MAX_STRING], address[MAX_STRING], email[MAX_STRING];
struct BST_node *b;
struct double_linked_list *l;
struct customer *c;
printf("\nADDING NEW CUSTOMER\n=\n\n");
printf("Give name (up to %d characters): ", MAX_STRING-1);
gets(name);
printf("Give address (up to %d characters): ", MAX_STRING - 1);
gets(address);
printf("Give email (up to %d characters): ", MAX_STRING - 1);
gets(email);
b = BST_find_customer(BST_email_root, email);
if (b)
{
printf("Duplicate email. Customer aborted.\n");
return 0;
}
c = (struct customer *) malloc(sizeof(struct customer));
if (c == 0)
{
printf("Not enough memory.\n");
return 0;
}
c->name = strdup(name); // check for memory allocation problem
if (c->name == 0) return 0;
c->address = strdup(address); // check for memory allocation problem
if (c->address == 0) return 0;
c->email = strdup(email); // check for memory allocation problem
if (c->email == 0) return 0;
l = (struct double_linked_list*) malloc(sizeof(struct double_linked_list));
if (l == 0)
{
printf("Not enough memory.\n");
free(c->name);
free(c->address);
free(c->email);
free(c);
return 0;
}
l->data = c;
l->previous = 0;
l->next = customers_head;
if (customers_head)
customers_head->previous = l;
customers_head = l;
BST_email_root = new_BST_node(BST_email_root, l);
return l;
}
void displaymenu() {
printf("\n\n");
printf("1. New customer\n");
printf("2. Find customer using email\n");
printf("0. Exit\n\n");
printf("Give a choice (0-6) : ");
}
void flush()
{
char ch;
while ((ch = getchar()) != '\n' && ch != EOF);
}
int main() {
int choice;
do {
displaymenu();
scanf("%d", &choice);
flush();
switch (choice) {
case 1:
new_customer();
break;
case 2:
find_customer();
break;
} while (choice != 0);
return 0;
}
On the line 69, you have to specify struct BST_node instead of BST_node:
root = (struct BST_node *) malloc (sizeof(struct BST_node ));
As for the rest of the code: read the manual for gets, it's clearly a function one should not use, I'd advise replacing it with fgets. There's also a little closing bracket missing in your final switch (line 178).
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.