2

This kind of questions might seem as one of those geeky considerations, but I rather ask you for thorough explanation of what is going on to satisfy my curiosity.

Let's assume we have a following chunk of code:

#include <stdio.h>

int main(void)
{
    char ch;

    scanf("%c", &ch);
    printf("%d\n", ch);

    return 0;
}

After compilation, one can type at the beginning of line simulated EOF with CTRL+Z shortcut and press ENTER - this is done twice.

Output looks like this:
^Z
^Z
-52
Press any key to continue . . .

1) What is happening right now?

I have another doubt concerning such loop:

while (scanf("%c", &ch) != EOF)
    printf("%c\n", ch);

printf("BYE!\n");

Output will be:
^Z
^Z
BYE!
Press any key to continue . . .

2) Why is not it terminating after first EOF simulation?

EDIT: I searched for another answers on SO relating to my doubts and I think that it is difficult to use scanf(), as it has got better substitutes like fgets() or fread(). Please take a look on another example below:

int input;
char ch;

while (scanf("%d", &input) != 1) //checking for bad input
    while ((ch = getchar()) != '\n') //disposing of bad input
        putchar(ch);

printf("BYE!\n");

I input five times CTRL+Z at the beginning of line and the output would become:
^Z
^Z
^Z
^Z
 ^Z
 ^Z
 ^Z
 ^Z
 ^Z
 ^Z
 ^CPress any key to continue . . .
I added five more EOFs and had to kill program with CTRL+C on the last line.

3) Why the space appeared on the 5-th line and was visible to the end (sometimes two spaces are before '^CPress any key to continue . . .')?

Last example is amendment of loop from above (there is no meaning in code):

while (scanf("%d", &input) != EOF);  

printf("BYE!\n");  

Output is:
^Z
^Z
^Z
BYE!
Press any key to continue . . .

4) Why are we using three times CTRL+Z instead of two as it was written in above comment?

MrDonMatti
  • 74
  • 5
  • 3
    (1) When you indicate EOF with Control-Z, nothing is assigned to `ch` so you get an indeterminate (semi-random) value printed for `ch`. (2) On Unix, if you indicated EOF (with Control-D, usually) as the first character of input, then you'd not need to repeat it; if you've typed a character, say a blank, and then type Control-D, that sends the blank to the program, but the programs continues to wait for a newline — or another EOF. If you're on Windows (plausible since you're using Control-Z rather than Control-D), the rules may be slightly different; you might have to indicate EOF twice always. – Jonathan Leffler Sep 26 '16 at 19:44
  • 1
    Step 1: Do not use `ch` when `scanf("%c", &ch) != 1` as in `scanf("%c", &ch); printf("%d\n", ch);` – chux - Reinstate Monica Sep 26 '16 at 19:47
  • @JonathanLeffler Thank You! I am using Windows right now and it might use double EOF simulation. What about if buffer (suppose we use line-buffering) has following chars: abc'EOF'\n? Why does it print graphical representation of control character and move carriage one position to the right instead of finishing one char before? – MrDonMatti Sep 26 '16 at 20:05
  • If you have type `abc` and then Control-Z once, the characters `abc` are made available to functions such as `getchar()`. Since `getchar()` doesn't care about newlines, the code should print `a` and then the loop-less code will exit. If you loop, the code will read the three characters and then wait for more input. If you type another Control-Z, the underlying `read()` system call returns 0 bytes available, which is the indication of EOF. If you use a line-based input (`fgets()` or POSIX `getline()`), those won't return the `abc` until either a newline or the EOF is read. – Jonathan Leffler Sep 26 '16 at 20:10
  • There are definitely other questions here on SO about EOF and typing Control-D or Control-Z to the program, and so on. One such is heavily Unix oriented, but may still help on Windows: [Canonical vs non-canonical terminal input](http://stackoverflow.com/questions/358342). There are almost certainly others more immediately relevant to you, but I missed them in my 30-minute scan (but I was doing some other clean-up etc while scanning, and the scan was using a not very focussed search). – Jonathan Leffler Sep 26 '16 at 20:42
  • @JonathanLeffler For sure, `getchar()` will include every char from console input and it works pretty well, when encountering simulated EOF - only one EOF at the beginning of line will exit the loop compared to two consecutive EOFs when using `scanf()`. Thanks again for efforts! – MrDonMatti Sep 26 '16 at 21:34

1 Answers1

0

Your code invokes undefined behavior. If scanf() cannot read a byte for format string "%c", it returns EOF and leaves ch uninitialized.

It is better to write the code this way:

while (scanf("%c", &ch) == 1)
    printf("%c\n", ch);

printf("BYE!\n");
chqrlie
  • 131,814
  • 10
  • 121
  • 189