5

A beginner's C book I'm reading has me confused with respect to getchar() and buffer order (especially as it relates to newline). It says,

Getting rid of the Enter keypress is a problem that all beginning C programmers must face. Consider the following segment of a program:

printf("What are your two initials?\n");
firstInit = getchar();
lastInit = getchar();

You would think that if the user typed GT, the G would go in the variable firstInit and the T would go in lastInit, but that's not what happens. The first getchar() doesn't finish until the user presses Enter because the G was going to the buffer. Only when the user presses Enter does the G leave the buffer and go to the program—but then the Enter is still on the buffer! Therefore, the second getchar() sends that Enter (\n) to lastInit. The T is still left for a subsequent getchar() (if there is one).

First, I don't understand the author's explanation as to why \n goes to lastInit rather than the T. I guess because I'm visualizing the buffer as “first in first out”. Either way I don't understand the logic behind the order the author is presenting—if the user enters G, then T, then Enter, how is it that the G is captured by the first getchar(), the Enter (newline) is captured by the second getchar(), and the T is captured by the third getchar()? Puzzling.

Second, I tried this myself (Ubuntu 14.04 running on VMWare under Windows 8.1, text editor Code::Blocks, compiler gcc), and I got the exact common-sense result that the author says doesn't happen!: The G goes to firstInit and the T goes to lastInit. Here is my code:

#include <stdio.h>

main()
{
  char firstInit;
  char lastInit;

  printf("What are your two initials?\n");

  firstInit = getchar();
  lastInit = getchar();

  printf("Your first initial is '%c' and ", firstInit);
  printf("your last initial is '%c'.", lastInit);

  return 0;
}

And the output is:

What are your two initials?
GT
Your first initial is 'G' and your last initial is 'T'.

I also created a follow-up program, which seems to confirm that newline comes out of the buffer last:

main()
{
  char firstInit;
  char lastInit;
  int newline;

  printf("What are your two initials?\n");

  firstInit = getchar();
  lastInit = getchar();
  newline = getchar();

  printf("Your first initial is '%c' and ", firstInit);
  printf("your last initial is '%c'.", lastInit);
  printf("\nNewline, ASCII %d, comes next.", newline);

  return 0;
}

And the output is:

What are your two initials?
GT
Your first initial is 'G' and your last initial is 'T'.
Newline, ASCII 10, comes next.

So am I missing something here or is the author wrong? (or is this compiler-dependent—even though the author didn't say so)?

Book: C Programming Absolute Beginner's Guide, 3rd edition, Greg Perry, ©2014, Ubuntu 14.04, gcc compiler version 4.8.4

yroc
  • 886
  • 1
  • 10
  • 16
  • Try typing "GT". – Andrew Henle Aug 03 '15 at 16:13
  • @AndrewHenle I can only type G before the program terminates. In this case firstInit captures the G and lastInit captures the newline, which is what I would expect. – yroc Aug 03 '15 at 16:18
  • 1
    Just type "GT". BTW `main` is incorrectly defined, should be `int main(void)`. – Weather Vane Aug 03 '15 at 16:20
  • 2
    Yep. You pretty much confirmed your book is wrong. And no, I don't know of any context where it would be correct, but it's hard to prove that it wasn't correct for the author when it was written. – Andrew Henle Aug 03 '15 at 16:23
  • @WeatherVane Hi, as I explained in my question, I did type GT, and I got a result different from what the author said, which is why I'm asking this question. In regards to main being incorrectly defined, I'm a beginner and just following the format of the book (he doesn't say anything about int main(void). Thank you. – yroc Aug 03 '15 at 16:25
  • The `stdin` buffer content is (usually) not passed to the program until `newline` is typed. But that `newline` is also read by `getchar()` just like any other char. I wonder what vintage book and compiler you use. I have an ancient compiler MSVC 9.0 but no probs here. Enter `GT` I get `GT`. Enter `GT` I get `G`. – Weather Vane Aug 03 '15 at 16:32
  • ... followed by "'T' is not recognized as an internal or external command, operable program or batch file." – Weather Vane Aug 03 '15 at 16:39
  • @WeatherVane I added the book and compiler info to the bottom of the question. In short, the vintage is very recent. I'm just puzzled that the author (in the 3rd edition of a book) would get such a different result. – yroc Aug 03 '15 at 16:42
  • You wrote *"I got the exact common-sense result that the author says doesn't happen!"*. So what use is the book? – Weather Vane Aug 03 '15 at 16:48
  • Well unless that obscure OS (Ubuntu ? Never heard of) inserts newlines at random into its input buffers, this book is off to a bad start. – Quentin Aug 03 '15 at 16:49
  • @Quentin I don't even use Linux but I know "Ubuntu" is a Linux distribution. OP's results conflict only with his book. – Weather Vane Aug 03 '15 at 16:50
  • @WeatherVane, Well perhaps the book is of little use (curiously, it gets high ratings on Amazon), but as a beginner I certainly don't feel I'm in a position to say I'm right and the book--ostensibly written by a C expert--is wrong. That's why I asked the expert community here. – yroc Aug 03 '15 at 16:55
  • An excellent decision indeed. I think it's not fair to judge the book by it's cover, but do take its advice on "surprising" matters with a grain of salt. It's probably not rubbish all the way through. – Quentin Aug 03 '15 at 16:58
  • You are making real progress when you can contradict the book, since none are perfect! But it's an easy trap to fall into, when convinced you are right ... but wrong. – Weather Vane Aug 03 '15 at 16:59
  • "_But it's an easy trap to fall into, when convinced you are right ... but wrong_" Indeed. – yroc Aug 03 '15 at 17:14

2 Answers2

3

The author is describing the scenario where the user types "G<enter>T<enter>".

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • That would certainly explain it, and you're probably right that this was the author's intention. But then the wording is misleading in my opinion: "...if the user typed GT" is not the same as "...if the user typed GT." Thank you. – yroc Aug 03 '15 at 18:12
2

This is a different example. The menu loop will iterate twice for each entered choice of 1, 2 or 3.
Remove the comment, //, from //while ( ( getchar ( ) != '\n')) {} and the buffer will be cleared after each entry and the menu will loop only once per entry.

#include <stdio.h>

int main()
{
    char *menu[] = { "1. first", "2. second", "3. third", "4. Exit"};
    int choice = 0;
    int each = 0;

    do {
        for ( each = 0; each < 4; each++) {
            printf ( "%s\n", menu[each]);
        }
        printf ( "\tenter choice 1-4\n");
        choice = getchar ( );
        //clear the buffer
        //while ( ( getchar ( ) != '\n')) {}
        printf ( "you entered %d %c\n", choice, choice);
    } while ( choice != '4');
    return 0;
}
user3121023
  • 8,181
  • 5
  • 18
  • 16