Why does this C code print only the first & last node entered? - c

#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char *Name;
int grade;
int cost;
}Hotel; /*This is data element in each node*/
typedef struct hinfo
{
Hotel h;
struct hinfo *next;
}Hinfo; /*This is a single node*/
typedef struct
{
Hinfo *next; /*This is the head pointer of the linked list*/
}HotelHead;
void createHotel(HotelHead *h);
void DisplayHotel(HotelHead h);
int main()
{
HotelHead *list=(HotelHead *)malloc(sizeof(HotelHead));
list->next=NULL;
createHotel(list);
DisplayHotel(*list);
return(0);
}
void createHotel(HotelHead *h) /*This function creates the list of hotels*/
{
char ans='y';
while(ans=='y' || ans=='Y')
{
char *name=(char *)malloc(20*sizeof(char));
Hinfo *new=(Hinfo *)malloc(sizeof(Hinfo));
printf("\nEnter hotel name: ");
scanf("%[A-Za-z0-9 ]",name);
printf("\nEnter hotel grade & cost: ");
scanf("%d %d",&new->h.grade,&new->h.cost);
new->h.Name=name;
new->next=NULL;
if(h->next==NULL){h->next=new;}
else
{
Hinfo *current=h->next;
while(current->next!=NULL){current->next=current->next->next;}
current->next=new;
}
printf("\nEnter another hotel?(Y/N): ");
scanf("%s",&ans);
getchar(); /*dummy getchar to eat unwanted character*/
}
}
void DisplayHotel(HotelHead h) /*This function displays all hotels in the list*/
{
Hinfo *current=h.next;
printf("\nHotel list:\n");
while(current!=NULL)
{
printf("\n%s %d %d\n",current->h.Name,current->h.grade,current->h.cost);
current=current->next;
}
}

You want to move current while walking the list instead of changing the value of current->next. Change this:
while (current->next != NULL) {
current->next = current->next->next;
}
to this:
while (current->next != NULL) {
current = current->next;
}
That said, it would be better to move current while adding new nodes instead of walking the linked list from the start every time. For example (skeleton code):
Hinfo *current;
while (...) {
Hinfo *new = malloc(sizeof(Hinfo));
// initialize new node
if (current != NULL) {
current->next = new;
}
current = new;
// prompt to enter more nodes
}

The DisplayHotel function is OK! The problem is with createhotel function.
When you do:
while( current->next != NULL ){
current->next = current->next->next;
}
Here you are actually changing the list, removing an element.
Try doing:
while( current->next != NULL ){
current = current->next;
}
Also the best approach would be to always have a pointer to the last element of the list on the head, so you add new elements directly instead of always going thorough the entire list! (remember to update the head when you add a new element)

This is incorrect:
char *name=(char *)malloc(sizeof(20));
You are allocating (sizeof(int)) bytes, not 20 bytes.
No matter what else you're doing, this will cause problems.

Related

printf segmentation fault and wrong sorted linked list

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.

How to use gets and puts with linked list using pointers

I've written a linked list program and want to take input with spaces but it's not working.It works fine when I simply use "scanf" with %s but since I want to take input with multiple spaces I tried using "gets" and "puts" I've also tried using scanf("%[^\n]*c"); but on the console it gives me random garbage value for scanf("%[^\n]*c"); and for "gets" it reads blank space,
now let me tell you guys some info about the code and how it works
createNode(); function basically just creates a new node to store in the list and returns the address of this newly created node to the insertend(); function where it aligns the new node at the end of the list and in start=t=newnode start is the head pointer which points to the very first node and t is used to traverse the list until t's value becomes NULL,As you could see in the else part of the insertend(); function we're using another pointer t and storing the value of start in it so that we can traverse the list without losing the the address of the first node which is originally kept in the start pointer.
here's the code ->
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
struct Node
{
char first[20];
struct Node* next;
};
struct Node* start=NULL;
struct Node* t,*u;
int i=1;
struct Node* createNode() //this function creates a newnode everytime it's called
{
struct Node* create=(struct Node*)malloc(sizeof(struct Node));
return create;
}
int length() //to measure the length of the list.
{
int count = 0;
struct Node* temp;
temp=start;
while(temp!=NULL)
{
count++;
temp = temp->next;
}
return count;
}
void insertend() //to insert a node at the end of the list.
{
int l;
struct Node* newnode = createNode();
printf("Enter Name : ");
fgets(newnode->first,sizeof(newnode->first),stdin);
if(start==NULL)
{
start=t=newnode;
start->next=NULL;
}
else
{
t=start;
while(t->next!=NULL)
t=t->next;
t->next=newnode;
t=newnode;
t->next=NULL;
printf("%s successfully added to the list!",newnode->first);
}
l=length();
printf("The length of the list is %d",l);
}
void display() //to display the list
{
struct Node* dis;
dis=start;
if(start==NULL)
{
system("cls");
printf("No elements to display in the list");
}
else
{
system("cls");
for(int j=1;dis!=NULL;j++)
{
printf("%d.) %s\n",j,dis->first);
dis=dis->next;
}
}
}
int menu() //this is just a menu it returns the user input to the main function
{
int men;
printf("Please select a choice from the options below :-\n\n");
printf("1.) Add at the end of the list\n");
printf("2.) Display list\n");
printf("3.) exit\n");
printf(" Enter your choice : ");
scanf("%d",&men);
return men;
}
int main()
{
while(1)
{
system("cls");
switch(menu())
{
case 1 : insertend();
break;
case 2 : display();
break;
case 3: exit(0);
default : system("cls"); printf("Ivalid choice!Please select an appropriate option!");
fflush(stdin);
break;
}
getch();
}
return 0;
}
gets is not to be used, it has been removed from C standard due to it's lack of security.
If you want to know more read Why is the gets function so dangerous that it should not be used?
If you use [^\n] it should work, though it's also problematic since this specifier does not limit the lenght of the stream to be read only that it must stop when finding a newline character.
I suspect the problem might be in the container rather than in the reading, maybe uninitialized memory, If you provide the struct code it'll be easier to diagnose.
You can try:
fgets(newnode->first, sizeof(newnode->first), stdin)
There is a caveat:
If the inputed stream is larger than the container, the extra characters will remain in the input buffer, you might need to discard them.
EDIT:
So the main problem was the fact that through your code you have lingering characters in the buffer, in the particular case of your fgets input it would catch a '\n' left in the buffer, so it would read it before the inputed stream, leaving it, again, in the buffer.
I added a function to clean up buffer, note that fflush(stdin) leads to undefined behaviour so it's a bad option.
I also added a few small tweaks.
- Note that conio.h is windows specific as is system("cls") and getch()(ncurses.h in Linux systems) so I commented it for this sample.
Live sample here
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
struct Node
{
char first[20];
struct Node *next;
};
struct Node *start = NULL;
struct Node *t, *u;
void clear_buf(){ //clear stdin buffer
int c;
while((c = fgetc(stdin)) != '\n' && c != EOF){}
}
struct Node *createNode() //this function creates a newnode everytime it's called
{
struct Node *create = malloc(sizeof(struct Node));
return create;
}
int length() //to measure the length of the list.
{
int count = 0;
struct Node *temp;
temp = start;
while (temp != NULL)
{
count++;
temp = temp->next;
}
return count;
}
void insertend() //to insert a node at the end of the list.
{
int l;
struct Node *newnode = createNode();
printf("Enter Name : ");
clear_buf(); //clear buffer before input
fgets(newnode->first, sizeof(newnode->first), stdin);
newnode->first[strcspn(newnode->first, "\n")] = '\0'; //remove '\n' from char array
if (start == NULL)
{
start = t = newnode;
start->next = NULL;
printf("%s successfully added to the list!", newnode->first);
}
else
{
t = start;
while (t->next != NULL)
t = t->next;
t->next = newnode;
t = newnode;
t->next = NULL;
printf("%s successfully added to the list!", newnode->first);
}
l = length();
printf("The length of the list is %d", l);
}
void display() //to display the list
{
const struct Node *dis;
dis = start;
if (start == NULL)
{
system("cls");
printf("No elements to display in the list");
}
else
{
system("cls");
for (int j = 1; dis != NULL; j++)
{
printf("%d.) %s\n", j, dis->first);
dis = dis->next;
}
}
}
int menu() //this is just a menu it returns the user input to the main function
{
int men;
printf("\nPlease select a choice from the options below :-\n\n");
printf("1.) Add at the end of the list\n");
printf("2.) Display list\n");
printf("3.) exit\n");
printf(" Enter your choice : ");
scanf("%d", &men);
return men;
}
int main()
{
while (1)
{
system("cls");
switch (menu())
{
case 1:
insertend();
break;
case 2:
display();
break;
case 3:
exit(0);
default:
system("cls");
printf("Ivalid choice!Please select an appropriate option!");
clear_buf();
break;
}
getch();
}
return 0;
}

How can I insert/add and delete a string in a list through a function in C?

It seems that my code isn't working because I cannot add any string to the list. It seems like the list remains empty. After every input of a string like "asd" or a single character, the message that appears every time is:
List is empty
Also, I don't know if the 'delete' function could work, because the 'insert' function isn't working.
Here's my code(It is a bit long):
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct listnode
{
char data[100];
listnode *nextPtr;
};
Here is my insert function. PS: I want to insert names so they can be alphabetically ordered.
void insert(struct listnode *strPtr, char value[])
{
struct listnode *previousPtr, *currentPtr, *newPtr;
newPtr=(listnode*)malloc(sizeof(listnode));
strcpy(newPtr->data,value);
newPtr->nextPtr=NULL;
previousPtr=NULL;
currentPtr=strPtr;
if(newPtr!=NULL)
{
while(currentPtr!=NULL && strcmp(currentPtr->data,value)>0)
{
previousPtr=currentPtr;
currentPtr=currentPtr->nextPtr;
}
if(previousPtr==NULL)
{
newPtr->nextPtr=strPtr;
strPtr=newPtr;
}
else
{
previousPtr->nextPtr=newPtr;
newPtr->nextPtr=currentPtr;
}
}else printf("%s was not inserted. Insuffiecient memory!",value);
}
Here is my delete function
const char *del(struct listnode* strPtr, char value[])
{
struct listnode *previousPtr, *currentPtr, *tempPtr;
if(strcmp(value, strPtr->data)==0) /*if the first node shall be
deleted*/
{
/*delete node*/
tempPtr=strPtr;
strPtr=strPtr->nextPtr;
free(tempPtr);
return value;
}
else
{
previousPtr=strPtr;
currentPtr=strPtr->nextPtr;
while(currentPtr!=NULL && strcmp(value, currentPtr->data)!=0)
{
previousPtr=currentPtr;
currentPtr=currentPtr->nextPtr;
}
if(currentPtr!=NULL)
{
tempPtr=currentPtr;
previousPtr->nextPtr=currentPtr->nextPtr;
free(tempPtr);
return value;
}
}
return '\0';//daca nu s-a gasit nodul
}
void instructions(void)
{
printf( "Options:\n"
" 1 to insert a name in the list.\n"
" 2 to delete a name from the list.\n"
" 3 to exit.\n" );
}
void printList(struct listnode *currentPtr)
{
if(currentPtr==NULL)
printf("List is empty\n");
else
{
printf("List is:\n");
while(currentPtr!=NULL)
{
printf("%s -->",currentPtr->data);
currentPtr=currentPtr->nextPtr;
}
}
}
int Empty(struct listnode *strPtr)
{
return strPtr == NULL;
}
int main()
{
struct listnode* startPtr;
startPtr=NULL;
int optiune;
char nume[100];
instructions();
printf("->> ");
scanf("%d",&optiune);
Here is the menu
while(optiune!=3)
{
switch(optiune)
{
case 1:
printf("Enter name:");
fflush(stdin);
gets(nume);
insert(startPtr, nume);
printList(startPtr);
break;
case 2:
printf("Search by name to delete from list:");
gets(nume);
if(!Empty(startPtr))
{
if(del(startPtr, nume))
{
printf("%s a fost sters din lista!\n");
printList(startPtr);
}else printf("%s nu a fost gasit!\n",nume);
}else
printf("List is empty!");
break;
case 3:
break;
default:
printf("No such option!\n\n");
instructions();
break;
}
printf("\n->> ");
scanf("%d",&optiune);
}
printf("Execution stopped.\n" );
return EXIT_SUCCESS;
}
I think I got it to work.
First thing I changed in your code was defining your struct as a typdef.
typedef struct{
char data[100];
struct listnode *nextPtr;
}listnode;
This is how I learned and it makes it easier to declare variables of this struct type, since we can just type "listnode" instead of "struct listnode" all the time.
Since you didn't give us the full code, I had to remove some things so I could compile it. As you are just asking why the list remains empty after the "insert" function I think this is fine for you.So here's the "main()" and "printlist()" functions that I used:
void printList(listnode *strPtr){
listnode *currentPtr = malloc(sizeof(listnode));
//Setting the ptr to run the list
currentPtr = strPtr;
if(strPtr == NULL) printf("Fail\n");
//Printing the list,while next is different than NULL keep going
printf("\nListing:\n");
while(currentPtr->data != NULL){
printf("%s\n",currentPtr->data);
currentPtr = currentPtr->nextPtr;
}
}
int main(){
char nume[128];
listnode *startPtr = NULL;//Initializing the fisrt ptr
//Reading the name
printf("Enter name:\n");
scanf("%s",nume);
//Inserting and printing the list
insert(&startPtr,nume);
insert(&startPtr,"Hello");
printList(startPtr);
return 0;
}
Some pretty basic stuff. Now to the main point:
As our friends told us in the comments, in C, the pointer is passed by value. It means that whatever changes you make in the function, it will not modify the startPtr variable in main().
To fix that all he have to do is to add one extra '*' on the function parameters. This means that we are now passing the strPtr argument by reference.
Here's the final function:
void insert(listnode **strPtr,char value[]){
listnode *previousPtr, *currentPtr,*newPtr;
//Allocating the nodes
newPtr = malloc(sizeof(listnode));
currentPtr = malloc(sizeof(listnode));
//Initializing the new node and setting the currentPtr
strcpy(newPtr->data,value);//Copying the name to the new node
newPtr->nextPtr = NULL;
currentPtr = strPtr;
//Previous is NULL
previousPtr = NULL;
if(newPtr != NULL){
//If there's already a node in the list let's find the right location
//For the new one(sorting)
while(currentPtr != NULL && strcmp(currentPtr->data,value) > 0){
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}
//If previous is NULL than this is the first node,no while iterations
//Note:strPtr is passed by reference,extra '*' needed
if(previousPtr == NULL){
newPtr->nextPtr = *strPtr;
*strPtr = newPtr;
}else{
previousPtr->nextPtr = newPtr;
newPtr->nextPtr = currentPtr;
*strPtr = newPtr;
}
}else{
printf("%s was not inserted. Insuffiecient memory!",value);
}
}
Note that we are also using an extra '*' when setting the newPtr to strPtr.This will modify the actual variable startPtr from main().
From that I hope you can also fix the delete function!
Don't forget to free the memory!
Also, don't forget to comment your code. It's really important to help you and other people to understand it, no matter how easy it might be!
Cheers!

Program updates Linked List

I am trying to create a linked list with names, for example:
Tom -> David -> John...
In my main function, I have a switch menu where the program asks if you want to create a new list or exit.
When the user choose 1, the program calls insertIntoLinkedList(name, &head) function where the user can add name(s) or type "end" to exit.
Everything works fine, however if the user enter end and choose option 1 again, the program creates a new linked list whereas I want to add names to an existing list.
Can someone please help me to figure out my problem? Thank you for your time.
EDIT
Here is my source code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NAME_SIZE 30
#define EXIT "end"
// Node structure
struct node {
char name[NAME_SIZE];
struct node *next;
};
typedef struct node Node;
typedef struct node* NodePointer;
int userChoice(void);
void insertIntoLinkedList(char [], NodePointer *);
void displayNames(NodePointer);
int nodeCounter = 0;
int main(void) {
int choice = 99;
do {
printf("\n--- MENU ---\n\n");
printf("1.\tCreate a new friend list\n");
printf("2.\tExit o_O");
printf("\n\n------------\n");
printf("Go to:\t");
choice = userChoice();
switch (choice) {
case 1: {
char name[NAME_SIZE] = "";
NodePointer head = NULL;
while(0 != strcmp(name, EXIT)){
printf("Enter new friend name or \"%s\" to return back to the main menu: ", EXIT);
scanf("%s", name);
if(0 != strcmp(name, EXIT)){
insertIntoLinkedList(name, &head);
displayNames(head);
}
}
displayNames(head);
break;
}
case 2: {
printf("\n\nYou have %d node(s) in your linked list. Have a great day.\n\n", nodeCounter);
break;
}
default:
printf("There is no such option. Please choose one of the option from 1 to 2.\n");
}
} while(choice != 2);
return 0;
}
int userChoice() {
int num;
scanf("%d", &num);
return num;
}
void insertIntoLinkedList(char word[], NodePointer *head){
NodePointer newNode = NULL;
NodePointer previous = NULL;
NodePointer current = *head;
newNode = malloc(sizeof(Node));
if(NULL != newNode){
strcpy(newNode -> name, word);
while(NULL != current && strcmp(word, current -> name) > 0){
previous = current;
current = current -> next;
}
if(NULL == previous){
newNode -> next = current;
*head = newNode;
} else {
previous -> next = newNode;
newNode -> next = current;
}
}
}
void displayNames(NodePointer current) {
nodeCounter = 0;
if(NULL == current){
printf("Friend list is empty... I am sorry :(\n\n");
return;
} else {
printf("\nCurrent friend list: ");
while(NULL != current){
nodeCounter++;
printf("%s → ", current -> name);
current = current -> next;
}
printf("\nNumber of friends in your current list:\t%d\n\n", nodeCounter);
}
}
Well U Can Just Declare A New Function For That. Because Every Time You Call This Function Head Is Re-declared .
E.g case 3:printf("\nEnter A New Friend Name:\n");
scanf("%s",name);
insertIntoLinkedList(name, &head);
displayNames(head);
break;
Everything works fine, however if the user enter end and choose option 1 again, the program creates a new linked list whereas I want to add names to an existing list.
The issue is that you have to declare the pointer which sores the head of the list outside the while loop.
NodePointer head = NULL;
do {
....
switch (choice) {
case 1: {
char name[NAME_SIZE] = "";
while(0 != strcmp(name, EXIT)){
....
}
....
}
} while(choice != 2);
Note you have declared the variable in the block scope inside the case. See Scope rules in C.
At the end of the scope the variable is not longer accessible and its content is lost. When you "reach" the code the next time, the you get a completely new initialized variable.

Adding a node containing multi-digit number at the nth position in a linked list

I have written a code for inserting a node at nth position.
When a user inputs 1 digit number in a node then it works perfectly but when user inputs equal to or more than two digit numbers then its keep on printing the last node only in infinite loop.
I couldn't figure out what's went wrong. My code is below
#include<stdio.h>
#include<stdlib.h>
struct st
{
int roll;
char name[20];
struct st *next;
};
void add_middle(struct st **ptr)
{
struct st *temp,*temp1;
temp=malloc(sizeof(struct st ));
printf("netre ur name\n");
scanf("%s",temp->name);
printf("enter ur roll\n");
scanf("%d",&(temp->roll));
if((*ptr==NULL)||(temp->roll<(*ptr)->roll))
{
temp->next=*ptr;
*ptr=temp;
}
else
{
temp1=*ptr;
while(temp1)
{
if((temp1->next==NULL)||(temp1->next->roll>temp->roll))
{
temp1->next=temp;
temp->next=temp1->next;
break;
}
temp1=temp1->next;
}
}
}
void display(struct st *ptr)
{
while(ptr)
{
printf("%s %d\n",ptr->name,ptr->roll);
ptr=ptr->next;
}
}
main()
{
struct st *headptr=0;
add_middle(&headptr);`
add_middle(&headptr);
add_middle(&headptr);
display(headptr);
}
Let's look at what happens when you insert the new node:
temp1->next = temp;
temp->next = temp1->next;
This will make the previous node (temp1) point to the new node, which is good. It will then have the new node (temp) point to itself (temp1->next == temp), which is bad.
To fix this, you can just swap those two lines. That is:
if ((temp1->next==NULL) || (temp1->next->roll > temp->roll)) {
temp->next = temp1->next;
temp1->next = temp;
break;
}
Additionally, this could be much clearer if you used better variable names:
temp1 becomes previousNode
temp becomes newNode

Resources