2

The following code snippet has been taken from Teach Yourself C by Herbert Schildt page 234.

#include <stdio.h>

int main(void)
{
    char ch;
    do
    {
        ch = getchar(); //suppose asdf is input
        putchar('.');
    } while (ch != '\n');
    return 0;
}

Which returns,

asdf
.....
Process returned 0 (0x0)   execution time : 0.050 s
Press any key to continue.

After this snippet Herbert Schildt writes, "Instead of printing a period between each character, what you will see on the screen is all the letters you typed before pressing ENTER, followed by a string of periods."

I am stuck with this snippet for a while. I tried some variations of the snippet to understand it better, which raised more questions than answering. This is actually running against my current understanding. Rather than printing out the above output, my current understanding suggests the following output:

asdf //input asdf
.
asd //input asd
.
\n //hit ENTER
.
Process returned 0 (0x0)   execution time : 0.050 s
Press any key to continue.

With the above introduction, I have the following questions:

  1. How the above snippet is looping even?
  2. What am I wrong with my current intuition?
Ahmed
  • 147
  • 7
  • 3
    I am not familiar with this particular book, however the name _Herbert Schildt_ raises a red flag for me. I recall that author having a reputation of writing bad books about C. [You might want to take a look at this, though it is about a different C book by the same author.](https://www.seebs.net/c/c_tcn4e.html) – Avi Berger Dec 06 '22 at 17:42
  • 2
    Some the actual details of how "keyboard" input is handled, and the interactions between the various subsystems involved, can be surprisingly complicated. I can recommend [this answer](https://stackoverflow.com/questions/9180001#51173273), [these course notes](https://www.eskimo.com/~scs/cclass/notes/sx6b.html), and [this other question](https://stackoverflow.com/questions/34806490). – Steve Summit Dec 06 '22 at 17:44
  • 3
    While it won't cause a problem in this particular program, it's generally a bug to use `char` as the type of a variable (like `ch` here) that will use to hold data returned by `getchar`. `ch` should, paradoxically, be declared as `int`. – Steve Summit Dec 06 '22 at 17:52

2 Answers2

2

From the C Standard:

C17 § 7.21.3p7:

the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device

From the ANSI C standard:

Description:

"putchar" outputs a character to the standard output "stdout" and returns the character that was written.

By default, all output streams (including "stdout" and "stderr") are normally buffered. This means that a number of characters are saved internally in a memory area called a buffer. When the buffer is full, the characters are then written out as a group. If a program requests input from terminal for which there is buffered output, the output is automatically "flushed" to the terminal, after which the input function begins reading input.

From this, you may infer that getchar() isn't given anything until a \n is seen.

Harith
  • 4,663
  • 1
  • 5
  • 20
1

Schildt has a reputation of not really understanding the difference between the C language and the environment the program runs in (among other things) [1, 2, 3]. You might be better served by another book.

But as for your specific question, here's what will generally happen.

The user hits the asdf keys. The operating system could choose to send them to the program immediately, but it's common for it to store them in a buffer until either 1) the buffer gets full or 2) the user enters a newline. The book assumes the buffering happens in this manner. The shell will also frequently echo the characters you're typing, so after typing asdf, "asdf" appears on the screen.

So when you type Enter, the program receives all the input (in the stdin stream) at once. (From this point forward, the behavior is governed entirely by C.) But getchar() only fetches one character from stdin at a time, so each time through the loop, it reads one character, then prints '.'. Upon reading the newline (and printing the corresponding '.'), the loop exits (without printing a trailing newline, although the environment might choose to add one).

Ray
  • 1,706
  • 22
  • 30
  • 1
    @SteveSummit Thanks. I thought I remembered some bash setting that could toggle that, but I suppose it was just forwarding to a system call. I've corrected the answer. – Ray Dec 06 '22 at 17:54
  • Adding another `putchar(ch);` in the loop my help understand. – Ahmed Dec 07 '22 at 06:31