Search code examples
cstringinputstructstructure

My inputs are getting skipped when using gets


I can't take the input for the name of the book for the loops i = 2 and i = 3.

It is getting skipped. The first input for i = 1 is running absolutely fine.

My code:

#include<stdio.h>

typedef struct book
{
    char name[100];
    float price;
    int pages;  
}bk;

int main(void)
{
    int i;
    bk b[100];
    // b1, b2, b3;
    for(i=1;i<=3;i++)
    {
        printf("Enter name of book %d: ",i);
        gets(b[i].name);
        printf("Enter price of book %d: ",i);
        scanf("%f",&b[i].price);
        printf("Enter pages of book %d:",i);
        scanf("%d",&b[i].pages);
    }
    printf("\nYour inputs are:");   
    for(i=1;i<=3;i++)
    {
        printf("\nName of book %d: %s",i,b[i].name);
        printf("\nPrice of book %d: %f",i,b[i].price);
        printf("\nPages of book %d: %d",i,b[i].pages);
    }
    return 0;
}

How should I fix this?


Solution

  • The first thing you need to remember is to never use gets again, more on that here.

    The second is to not mix gets (or rather fgets, which is what you should use to replace gets) and scanf.

    The root of your problem is that in the second loop, gets reads the newline character left in the buffer by the scanf at the end of the loop, making it seems as though it was skipped, it was not, if you print b[2].name you'll see that it has a newline character.

    Your code should look more like this:

    void clear_buffer(){ //helper function to clear buffer when needed
        int c;
        while((c = getchar()) != '\n' && c != EOF){}
        printf("Bad input, try again: ");
    }
    
    //...
    int main(void)
    {
        int i;
        bk b[100];
        for (i = 0; i < 3; i++)
        {
            printf("Enter name of book %d: ", i);
            while(scanf(" %99[^\n]", b[i].name) != 1){ // mind the space before specifer
                clear_buffer(); 
            }
            printf("Enter price of book %d: ", i);
            while(scanf("%f", &b[i].price) != 1){
                clear_buffer(); // if the value was not parsed correctly, ask again
            }
            printf("Enter pages of book %d:", i);
            while(scanf("%d", &b[i].pages) != 1){
                clear_buffer();
            }
        }
        //...
        //rest of the code
    }
    

    The code has some improvements:

    1. Using scanf(" %99[^\n]", b[i].name) makes sure that there will be no buffer overflow, it will read, at most 99 caracters, reserving a space for the null terminator, which is something gets cannot do, that's why it was removed from the language, though some compiler still support it, I can't immagine why.

    2. I'm checking if the scanf really parses the values, if not, let's say someone inputs a character instead of a digit, it asks again, instead of entering an infinite loop which is what would happen before.

    3. for (i = 0; i < 3; i++) makes sure the array is being populated from index 0, the way you have it, it will not use the first element of the array, you'll have to fix the printf accordingly..