creating a binary search tree with strings - c

#include<stdio.h>
#include<conio.h>
#include<malloc.h>
#include<string.h>
struct node{
char *name;
struct node *lchild;
struct node *rchild;
}*root;
void find(char *str,struct node **par,struct node **loc)
{
struct node *ptr,*ptrsave;
if(root==NULL)
{
*loc=NULL;
*par=NULL;
return;
}
if(!(strcmp(str,root->name)))
{
*loc=root;
*par=NULL;
return;
}
if(strcmp(str,root->name)<0)
ptr=root->lchild;
else
ptr=root->rchild;
ptrsave=root;
while(ptr!=NULL)
{
if(!(strcmp(str,ptr->name)))
{
*loc=ptr;
*par=ptrsave;
return;
}
ptrsave=ptr;
if(strcmp(str,ptr->name)<0)
ptr=ptr->lchild;
else
ptr=ptr->rchild;
}
*loc=NULL;
*par=ptrsave;
}
void insert(char *str)
{
struct node *parent,*location,*temp;
find(str,&parent,&location);
if(location!=NULL)
{
printf("Name already present\n");
return;
}
temp=(struct node*)malloc(sizeof(struct node));
temp->name=str;
temp->lchild=NULL;
temp->rchild=NULL;
if(parent==NULL)
root=temp;
else
if(strcmp(str,parent->name)<0)
parent->lchild=temp;
else
parent->rchild=temp;
}
void displayin(struct node *ptr)
{
if(root==NULL)
{
printf("Tree is empty");
return;
}
if(ptr!=NULL)
{
displayin(ptr->lchild);
printf("%s -> ",ptr->name);
displayin(ptr->rchild);
}
}
int main()
{
root=NULL;
char str[20];
while(1)
{
printf("Enter name: ");
fflush(stdin);
gets(str);
insert(str);
printf("Wants to insert more item: ");
if(getchar()=='y')
insert(str);
else
break;
}
displayin(root);
getch();
getchar();
return 0;
}
If i run this piece of code with following input
rakesh
rajesh
bimal
then,it is displaying the output as "bimal->" which is wrong. I don't know where the logic is going wrong. I crosschecked but not able to find mistake. Can somebody take a look on this.

One of the issue:
In your insert() function you are doing
temp=(struct node*)malloc(sizeof(struct node));
temp->name=str; //this is not correct,
//do
temp=malloc(sizeof(struct node)); // no type cast for malloc
temp->name = strdup(str); //allocate memory too
//also check you NULL and free the allocated memory.
Your are just setting the pointer location in the node you created for string to store, but it points to str array from main(). So all nodes will point to same location, which will have last value entered. In your case its "bimal".

Your find function is in any case quite obscure. This is the improved version.
void find(char *str,struct node **par,struct node **loc)
{
*par = NULL;
*loc = NULL;
struct node *ptr,*ptrsave;
if(root==NULL) return;
if(!(strcmp(str,root->name)))
{
*loc=root;
return;
}
ptrsave = NULL;
ptr = root;
while(ptr!=NULL) {
if(!(strcmp(str,ptr->name))) break;
ptrsave = ptr;
if(strcmp(str,ptr->name)<0)
ptr=ptr->lchild;
else
ptr=ptr->rchild;
}
*loc=ptr;
*par=ptrsave;
}

Related

Why my linked list is displaying garbage values

My doubly Linked list in C is displaying garbage value instead of value that I have entered, I have run this code on Turbo C++.
the code compiled correctly with 0 errors and 0 warnings, but still it is displaying some garbage values. I have included the libraries (stdio.h,conio.h,stdlib.h,malloc.h)
here is the code :
struct dlist
{
int data;
struct dlist *next;
struct dlist *prev;
};
struct dlist *head, *end;
void create_dlist()
{
char k='y';
struct dlist *new_node;
while(k=='y'||k=='Y') {
if(head==NULL) {
new_node=(struct dlist *)malloc(sizeof(struct dlist));
printf("Enter the integer value -> ");
new_node->data=0;
new_node->next=NULL;
new_node->prev=NULL;
scanf("%d",&new_node->data);
head=new_node;
end=new_node;
} else {
new_node=(struct dlist *)malloc(sizeof(struct dlist));
printf("Enter the integer value -> ");
new_node->data=0;
new_node->next=NULL;
new_node->prev=end;
scanf("%d",&new_node->data);
end->next=new_node;
end=new_node;
}
printf("Do you want to continue (y/n) ; ");
scanf(" %c",&k);
}
}
void display()
{
struct dlist *pointer;
pointer=head;
if(pointer!=NULL) {
while(pointer->next!=NULL) {
printf("%d\t",&pointer->data);
pointer=pointer->next;
}
} else {
printf("list is empty");
}
}
int main()
{
clrscr();
head=NULL;
end=NULL;
create_dlist();
display();
getch();
return 0;
}
A coded solution will be a great help
Whole problem is in display(). First you print address and not value of data. Also, you are not printing last element. I made some changes. Ask me if you need any explanations.
void display()
{
struct dlist *pointer;
pointer=head;
if(pointer!=NULL)
{
while(pointer!=NULL)
{
printf("%d\t",pointer->data);
pointer=pointer->next;
}
}
else
{
printf("list is empty");
}
}

storing and printing string in void pointer

I have written a linked list program which stores data member as void *.
while trying to store annd print using scanf/printf functions, I am getting segmentation fault.
node definition -->
typedef struct node {
struct node *next;
void *data;
}node;
main function -->
head=(node *)malloc(sizeof(node));
if (head==NULL){
printf("error in allocation of memory\n");
exit(EXIT_FAILURE);
}
tail=(node*)create(head);
create function -->
void *create(node *current)
{
int user_choice;
while(current){
printf("\nEnter the data:");
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
current=current->next;
}
else{
current->next=NULL;
}
}
return current;
}
can anyone tell what is the correct argument for scanf & prinf should be..?
working code after incorporating points given in answers...
void *create(node *current)
{
node *temp;
int user_choice;
while(current){
printf("\nEnter the data:");
current->data=(char*)malloc(10*sizeof(char));
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
}
else{
current->next=NULL;
temp=current;
}
current=current->next;
}
return temp;
}
In your code,
scanf("%s",current->data);
is attempt to make use of an unitialized pointer, it invokes undefined behavior.
You need to follow either of bellow approach,
make the pointer point to valid chunk of memory (using malloc() and family for dynamic allocation, for example)
use an array.
You should first initialize data member of structure because
current->data = malloc("passes size here");
For putting data you have to typecast first this data because void is not storage type. void pointer can be used to point to any data type.
Like
*(char *)(current->data) = 1;
As others have said:
scanf("%s",current->data);
Is undefined in C. current->data needs to be pointing somewhere before you can store anything in it.
You should instead:
Accept input from scanf.
Store in temporary buffer.
Insert into linked list
print out whole linked list at the end
free() linked list at the end.
I also feel that your current void *create function is doing too much, and it would be easier to split up your code into different functions, just to make it easier to handle all the pointer operations, inserting etc.
To demonstrate these points, I wrote some code a while ago which does these things, and has been modified to help you with your code. It is not the best code, but it does use these points that will help you with your code.
Here it is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSTRLEN 100
typedef struct node {
void *data;
struct node *next;
} node_t;
typedef struct {
node_t *head;
node_t *foot;
} list_t;
list_t *create_list(void);
node_t *generate_node(void);
list_t *insert_node(list_t *list, char *data);
void print_list(list_t *list);
void free_list(list_t *list);
int
main(int argc, char *argv[]) {
list_t *list;
char data[MAXSTRLEN];
int user_choice;
list = create_list();
while (1) {
printf("Enter the data: ");
scanf("%s", data);
printf("\nType '1' to continue, '0' to exit:\n");
if (scanf("%d",&user_choice) != 1) {
printf("Invalid input\n");
exit(EXIT_FAILURE);
}
if (user_choice == 1) {
list = insert_node(list, data);
} else {
list = insert_node(list, data);
break;
}
}
print_list(list);
free_list(list);
list = NULL;
return 0;
}
/* inserting at foot, you can insert at the head if you wish. */
list_t
*insert_node(list_t *list, char *data) {
node_t *newnode = generate_node();
newnode->data = malloc(strlen(data)+1);
strcpy(newnode->data, data);
newnode->next = NULL;
if (list->foot == NULL) {
list->head = newnode;
list->foot = newnode;
} else {
list->foot->next = newnode;
list->foot = newnode;
}
return list;
}
node_t
*generate_node(void) {
node_t *new = malloc(sizeof(*new));
new->data = NULL;
return new;
}
void
print_list(list_t *list) {
node_t *curr = list->head;
printf("\nlinked list data:\n");
while(curr != NULL) {
printf("%s\n", (char*)curr->data);
curr = curr->next;
}
}
list_t
*create_list(void) {
list_t *list = malloc(sizeof(*list));
if (list == NULL) {
fprintf(stderr, "%s\n", "Error allocating memory");
exit(EXIT_FAILURE);
}
list->head = NULL;
list->foot = NULL;
return list;
}
void
free_list(list_t *list) {
node_t *curr, *prev;
curr = list->head;
while (curr) {
prev = curr;
curr = curr->next;
free(prev);
}
free(list);
}
UPDATE:
Also note how I allocated memory for newnode->data?
Like this:
newnode->data = malloc(strlen(data)+1); //using buffer from scanf
This now means I can store data in this pointer, your current->data will need to do something similar.
working code-->
void *create(node *current)
{
node *temp;
int user_choice;
while(current){
printf("\nEnter the data:");
current->data=(char*)malloc(10*sizeof(char));
scanf("%s",current->data);
printf("stored at %p\n",(void*)current->data);
printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
}
else{
current->next=NULL;
temp=current;
}
current=current->next;
}
return temp;
}
Please try with this
void *create(node *current)
{
int user_choice;
while(true){
if(current == NULL) {
current = (node *)malloc(sizeof(node));
current->data = NULL;
current->next = NULL;
}
printf("\nEnter the data:");
scanf("%s",current->data);
printf("stored at %p\n", (void *)current->data);
printf("%s",current->data);
//printf("%s",(char*)current->data);
printf("\nType '1' to continue, '0' to exit:\n");
scanf("%d",&user_choice);
if(user_choice == 1){
current->next=(node*)malloc(sizeof(node));
current=current->next;
}
else{
current->next=NULL;
tail = current;
current=current->next;
break;
}
}
return current;
}
Note: The element has to be initialized (ie; it has to be alloted with some memory) before we are trying to make use of it.

Printing strings in linked lists

So I'm having trouble getting my program to print both the strings I input, or however many you want to put in the list, it always prints out the last string inputted multiple times. I am sorry about all the commented out code, most of it you don't need to read.
#include<stdio.h>
#include<stdlib.h>
struct node{
char *data;
struct node *next;
}*head;
typedef struct node NODE;
// Function prototypes
void append(char myStr[]);
void add( char myStr[] );
//void addafter(char myStr[], int loc);
void insert(char myStr[]);
int delete(char myStr[]);
void display(struct node *r);
int count();
// main function
int main()
{
int i;
struct node *n;
head = NULL;
char myStr[50];
while(1)
{
printf("\nList Operations\n");
printf("===============\n");
printf("1.Insert\n");
printf("2.Display\n");
printf("3.Size\n");
printf("4.Delete\n");
printf("5.Exit\n");
printf("Enter your choice : ");
if(scanf("%d", &i) <= 0)
{
printf("Enter only an Integer\n");
exit(0);
}
else
{
switch(i)
{
case 1:
printf("Enter the name to insert : ");
scanf("%50s", myStr);
insert(myStr);
break;
case 2:
if(head == NULL)
{
printf("List is Empty\n");
}
else
{
printf("Name(s) in the list are : ");
}
display(n);
break;
case 3:
printf("Size of the list is %d\n",count());
break;
case 4:
if(head == NULL)
printf("List is Empty\n");
else
{
printf("Enter the myStrber to delete : ");
scanf("%50s",myStr);
if(delete(myStr))
printf("%s deleted successfully\n",myStr);
else
printf("%s not found in the list\n",myStr);
}
break;
case 5:
return 0;
default:
printf("Invalid option\n");
}
}
}
return 0;
}
// Function definitions
void append(char myStr[])
{
struct node *temp,*right;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = myStr;
right=(struct node *)head;
while(right->next != NULL)
{
right = right->next;
}
right->next = temp;
right = temp;
right->next = NULL;
}
// adding a node to the beginning of the linked list
void add( char myStr[] )
{
struct node *temp;
temp =(struct node *)malloc(sizeof(struct node));
temp->data = myStr;
// only one node on the linked list
if (head == NULL)
{
head = temp;
head->next = NULL;
}
else
{
temp->next = head;
head = temp;
}
}
void insert(char myStr[])
{
int c = 0;
struct node *temp;
temp = head;
if(temp == NULL)
{
add(myStr);
}
else
{
append(myStr);
}
}
int delete(char myStr[])
{
struct node *temp, *prev;
temp = head;
while(temp != NULL)
{
if(temp->data == myStr)
{
if(temp == head)
{
head = temp->next;
head = (*temp).next;
free(temp);
return 1;
}
else
{
prev->next = temp->next;
free(temp);
return 1;
}
}
else
{
prev = temp;
temp = temp->next;
}
}
return 0;
}
void display(struct node *r)
{
r = head;
if(r == NULL)
{
return;
}
while(r != NULL)
{
printf("%s ", r->data);
r = r->next;
if(r == NULL)
{
printf("\nOur linked list is finished!");
}
}
printf("\n");
}
int count()
{
struct node *n;
int c = 0;
n = head;
while(n != NULL)
{
n = n->next;
c++;
}
return c;
}
The problem seems to be that myStr at main function is a char[], so it's content is overritten every time you insert data. Notice that struct node data field is a char*, it's just pointing to myStr address.
Hope this help!
Your program has only one place to write your input, myStr.
With each input, myStr is erased and a something else is written to myStr.
The data member of all of the nodes, points to myStr. myStr will only contain the last input.
The display() function asks each node what is data. data points to myStr so each node prints the contents of myStr. myStr will only contain the last input so all the nodes print the last input.
To fix this, in the add() and append() functions, you need to give the data member some memory by using malloc(). Then copy the contents of myStr to the data member by using strcpy().
temp->data = malloc ( strlen ( myStr) + 1);
strcpy ( temp->data, myStr);
Do this instead of temp->data = myStr;
You will need #include<string.h>
The memory will need to be free()'d in the delete() function.
free(temp->data);
Do this before freeing temp
char *data
that variable from struct is always assigned with the address of myStr as its a pointer it would only show you the value of myStr

insert in Linked List Turbo C

I am trying to program a text editor in C. I am having trouble with inserting an element in a linked list. The program simply won't insert anything in the middle of the linked list.
#include <stdio.h>
#include <stdlib.h>
#include<conio.h>
I used singly linked list.
struct node {
struct node *previous;
int c;
int x;
int y;
struct node *next;
}*head;
this works fine:
void characters(int typed, int xpos, int ypos) //assign values of a node
{
struct node *temp,*var,*temp2;
temp=(struct node *)malloc(sizeof(struct node));
temp->c=typed;
temp->x=xpos;
temp->y=ypos;
if(head==NULL)
{
head=temp;
head->next=NULL;
}
else
{
temp2=head;
while(temp2!=NULL)
{
var=temp2;
temp2=temp2->next;
}
temp2=temp;
var->next=temp2;
temp2->next=NULL;
}
}
this works just fine too.
void printer() //to print everything
{
struct node *temp;
temp=head;
while(temp!=NULL)
{
gotoxy(temp->x,temp->y);
printf("%c",temp->c);
temp=temp->next;
}
}
this works just fine too:
void deletesEnd //delete at the end
{
struct node *temp,*last;
temp=head;
last=temp;
while(temp!=NULL && temp->next!=NULL)
{
last=temp;
temp=temp->next;
}
if(last==temp)
{
free(temp);
head=NULL;
}
else{
free(last->next);
last->next=NULL;
}
}
THIS IS THE PROBLEM:
void checker(int ch, int xpos, int ypos)
{
int flag=0;
struct node *temp,*temp1,*insert_node;
temp=head;
while(temp!=NULL)
{
if(temp->x==xpos && temp->y==ypos)
{
temp1=temp;
temp=insert_node;
insert_node->c=ch;
insert_node->x=xpos;
insert_node->y=ypos;
insert_node->next=temp1;
flag=1;
break;
}
else
temp= temp->next;
}
free(temp);
free(temp1);
if(flag==0)
characters(ch,xpos,ypos);
}
main()
{
int c; //for storing the character
int x,y; //for the position of the character
clrscr();
for(;;)
{
c=getch();
x=wherex();
y=wherey();
if(c==27)
exit(0);
else if(c==0|| c==224)
{
switch(getch())
{
case 72: //for up
gotoxy(x,y-1);
break;
case 80: //for down
gotoxy(x,y+1);
break;
case 75: //for left
gotoxy(x-1,y);
break;
case 77: //for right
gotoxy(x+1,y);
break;
}
}
else if(c==13)
{
printf("\n");
}
else if(c==8) //for backspace
{
deletesEnd();
clrscr();
printer();
}
else //for normal characters
{
checker(c,x,y);
// characters(c,x,y);
printer();
}
}
}
I tried to debug it, it goes inside the loop with the conditional statement of ((temp->x==xpos && temp->y==ypos)) Thus, the program is supposed to insert an element but it doesn't. :(
Maybe you have to malloc a struct node for the element you want to insert first, not just declare a struct node *.
Try to add struct node *insert_node = (struct node *)malloc(struct node) in your checker method.
Try concept of insertion from this one - It can insert a node from front end
Just make a new pointer to node and name it create
struct node *create;
int item;
printf("Enter a number you want to insert\n\t");
scanf("%d",&item);
create = (struct node*)malloc(sizeof(struct node*));
create->info = item;
create->ptr = first;
HEAD = create;

Simpler and faster code for reversing list?

I wrote the code for reversing a doubly linked list containing words in each node, which works perfectly fine.
My teacher says the algorithm is difficult to understand and the code as a whole could be made more efficient(reducing overhead and memory consumption). What changes can i make to the code/the reversing algorithm?
Also is there a way i could input the sentence without having to ask the number of words in advance? Here is the code:
#include<stdio.h>
#include<conio.h>
#include<string.h>
typedef struct NODE
{
char *item;
struct NODE *next;
struct NODE *prev;
}NODE;
void Insert(char data[],NODE **List)
{
NODE *temp,*last;
last=(*List);
temp=(NODE*)malloc(sizeof(NODE));
temp->item=(char*)malloc(strlen(data));
temp->item=data;
temp->next=NULL;
temp->prev=NULL;
if((*List)->item==NULL)
(*List)=temp;
else
{
while(last->next!=NULL)
last=last->next;
temp->prev=last;
last->next=temp;
last=temp;
}
}
void Reverse(NODE **List)
{
int flag1=0;
NODE *temp,*temp1,*last,*flag;
temp1=(NODE*)malloc(sizeof(NODE));
last=(*List);
while(last->next!=NULL)
last=last->next;
temp=last;
while(temp->prev!=NULL)
{
temp1->item=temp->item;
temp1->next=temp->next;
temp1->prev=temp->prev;
temp->next=temp->prev;
temp->prev=temp1->next;
temp=temp->next;
if(flag1==0)
{
flag1++;
flag=temp;
}
}
temp1->item=temp->item;
temp1->next=temp->next;
temp1->prev=temp->prev;
temp->next=NULL;
temp->prev=temp1->next;
(*List)=flag->prev;
free(temp1);
};
void display(NODE *List)
{
if(List->next==NULL)
{
printf("%s",List->item);
return;
}
NODE *temp;
temp=List;
do
{
printf("%s<-->",temp->item);
temp=temp->next;
}while(temp->next!=NULL);
printf("%s\n",temp->item);
}
int main()
{
int i=0,n;
char s[10][50];
NODE *List;
List=(NODE*)malloc(sizeof(NODE));
List->item=NULL;
List->next=NULL;
List->prev=NULL;
printf("Provide number of words(max 10): ");
scanf("%d",&n);
printf("Enter string of words for the list: ");
while(i<n)
{
scanf("%s",s[i]);
Insert(s[i],&List);
i++;
}
printf("\nOriginal List is: ");
display(List);
Reverse(&List);
printf("\nReversed List is: ");
display(List);
getch();
return 0;
}
Since it's a double-linked list you could just write two traversal functions. One forward and one reverse. Save two anchors for your list in your control structure: one for the first element and one for the last.
You can just swap the next and previous pointers for each node and swap tail and head pointers.
void reverse (struct node *ptr)
{
struct node *tmp, *kid;
if (!ptr) return;
for (kid = ptr->next; kid; kid = kid->prev) {
tmp = kid->prev;
kid->prev = kid->next;
kid->next = tmp;
}
for (kid = ptr->prev; kid; kid = kid->next) {
tmp = kid->prev;
kid->prev = kid->next;
kid->next = tmp;
}
tmp = ptr->prev;
ptr->prev = ptr->next;
ptr->next = tmp;
return;
}
Note: I removed the typedef. I hate typedefs.

Resources