2
votes

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?

1
(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
Step 1: Do not use ch when scanf("%c", &ch) != 1 as in scanf("%c", &ch); printf("%d\n", ch);chux - Reinstate Monica
@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
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
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. 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

1 Answers

0
votes

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");