cdata-structureslinked-listgetsputs

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;
}

Solution

  • 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:

    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;
    }