topcat
topcat

Reputation: 189

How does getchar() work in a While loop?

This part of a program confused me when I'm working in an exercise book.

Why do I get the same result when I swap the last if statement and while getchar()?

In both cases I get the sentence "Enter the next title." first. And in both cases I get getchar() second, waiting for an input with the cursor blinking.

Shouldn't putting the while(getchar()!= '\n'); continue; First make the program wait for an input before printing puts("Enter the next title.");?

My understanding that it should be stuck inside while loop until the condition of exit is present, then proceed to the next statement! which is the print

Here the if statement first:

while(count< MAXBKS && s_gets(library[count].title,MAXTITL) != NULL && library[count].title[0] != '\0')
    {
        puts("Now enter the author.");
        s_gets(library[count].author,MAXAUTL);
        puts("Now enter the value.");
        scanf("%f", &library[count++].value);
        if( count < MAXBKS)  //  1  //
            puts("Enter the next title.");
        while(getchar()!= '\n')  //  2  //
            continue;

    }

here the the while(getchar().. first:

while(count< MAXBKS && s_gets(library[count].title,MAXTITL) != NULL && library[count].title[0] != '\0')
{
    puts("Now enter the author.");
    s_gets(library[count].author,MAXAUTL);
    puts("Now enter the value.");
    scanf("%f", &library[count++].value);
    while(getchar()!= '\n')  //   2  //
        continue;

    if( count < MAXBKS)    //   1  //
        puts("Enter the next title.");
}

Here is the entire program for context:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10

char * s_gets(char * st, int n);
struct book
{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};


int main(void)
{
    struct book library[MAXBKS];
    int count = 0;
    int index, filecount;
    FILE *pbooks;
    int size = sizeof(struct book);

    if ((pbooks = fopen("book.dat", "a+b")) == NULL)
    {
        fputs("Can't open book.dat file\n", stderr);
        exit(1);
    }

    rewind(pbooks);
    while(count< MAXBKS && fread(&library[count],size,1, pbooks) == 1)
    {
        if (count ==0)
            puts("Current contents of book.dat:");
        printf("%s by %s: $%.2f\n", library[count].title, library[count].author, library[count].value);
        count++;
    }
    filecount = count;
    if(count == MAXBKS)
    {
        fputs("The book.dat file is full.\n", stderr);
        exit(2);
    }
    puts("Please add new book titles.");
    puts("Press [enter] at the start of a line to stop.\n");
    while(count< MAXBKS && s_gets(library[count].title,MAXTITL) != NULL && library[count].title[0] != '\0')
    {
        puts("Now enter the author.");
        s_gets(library[count].author,MAXAUTL);
        puts("Now enter the value.");
        scanf("%f", &library[count++].value);
        while(getchar()!= '\n')
            continue;

        if( count < MAXBKS)
            puts("Enter the next title.");
    }
    if(count>0)
    {
        puts("Here is a list of your books:");
        for(index =0; index < count; index++)
            printf("%s by %s: $%.2f\n", library[index].title, library[index].author, library[index].value);
        fwrite(&library[filecount],size,1,pbooks);
    }
    else
        puts("No books? Too bad.\n");
    puts("Bye.\n");
    fclose(pbooks);
    return(0);
}


char *s_gets(char *st, int n)
{
    char *ret_val;
    char *find;

    ret_val= fgets(st,n,stdin);
    if (ret_val)
    {
        find = strchr(st, '\n');
        if(find)
            *find = '\0';
        else
            while(getchar() != '\n')
                continue;
        }
        return (ret_val);
    }

Upvotes: 0

Views: 2916

Answers (1)

Pablo
Pablo

Reputation: 13570

Shouldn't putting the while(getchar()!= '\n'); continue; first make the program wait for an input before printing puts("Enter the next title.");?

No, while(getchar()!= '\n'); continue; will clear the input buffer1, it will not wait for user input. Then it will print the text. The reason why it doesn't wait for the user to enter something is that you had a scanf before. If it matches a float, it will convert that and save in &library[count++].value, however the newline will be left in the input buffer. That's why people use this method of clearing the rest in the input buffer. If it doesn't match anything, then the whole line will remain in the input buffer.

For this reason it doesn't matter which you execute first, the buffer will be cleared and your text will be printed. It is the fgets in the next s_gets() call which blocks and waits for user input, not the getchar().

My understanding that it should be stuck inside while loop until the condition of exit is present, then proceed to the next statement! which is the print

And so it did, you most likely misinterpreted who blocks and waits for the user input.

Some suggestions:

The clearing of the buffer is best done like this:

int c;
while( (c = getchar()) != '\n' && c != EOF);

Also it is better to always check the return value of scanf. It will return the number of successfull matches tokens. So if you expect one conversion, then check that scanf returns 1. If that's not the case, the input was wrong. You may decide to clear the buffer and let the user enter retry again.


1Obviously if the first reading code would be the while(getchar() != '\n') continue; then it would block and wait for user input, because the input buffer will be empty. But in your case, the input buffer is definitively not empty.

Upvotes: 2

Related Questions