3

I'm learning how input works in C. My biggest struggle is understanding EOF behaviour in the terminal
First, i'm using Windows and GCC compiler "In case this might help"
Second, i'm not trying to redirect input from a file... my question is about input from Windows console

My question:

I read that EOF closes the input stream, that you can't read from stdin after EOF... This is not the case for me! Even after i enter explicitly Enter-Ctrl-Z-Enter, if i do another getchar() call it reads from stdin... An example:

int c = 0;
char str[100]={0};

printf("Type in a string with spaces so some chars would remain in Stdin: ");
//Let's say i type "Hello world!"
scanf("%s",str);

while( (c=getchar()) != EOF )
    printf("%c",c);
//it displays " World!" in console, then i type Enter-^Z-Enter
//The loop exits so far so good

printf("Let's just check if we can still read from stdin, type a char: ");
c = getchar(); //i type the letter 'a'
printf("\nYou entered: %c\n",c); //It displays 'a'?!


Also, something strange happens when you type ^Z in the middle of string, any chars before it would be returned but anything typed after it disapprears! But when you check for the variable content it's not equal to -1? Here's an example:

int c = 0;
char str[100]={0};

printf("Type in a string with spaces so some chars would remain in Stdin: ");
//This time i type "Hello wor^Zld!" with ^Z in the middle of "World!"
scanf("%s",str);    

while( (c=getchar()) != EOF )
    printf("%c",c);
//it displays " Wor->" in console, with the cursor hanging waiting for input
/*
So on the one hand, after ^Z everything disappears, but on the other 
hand it's waiting for input so it's not EOF?!
*/

//In case you're wondering, here too i can call getchar() and read from stdin!
printf("Let's just check if we can still read from stdin, type a char: ");
c = getchar(); //i type the letter 'a'
printf("\nYou entered: %c\n",c); //It also displays 'a'?!


Believe me i'm really trying to understand how this works but it's really confusing for a beginner in C... So any help would be greatly appreciated!

360NS
  • 176
  • 1
  • 10

2 Answers2

1

Let me explain: the classic usage for this function is reads from files. Each file ends with EOF. stdin is "special file", because it doesn't have EOF. So how it works? Each time you hit Enter, the string you have typed inserted to the stdin buffer. Each call to getchar() reads single char from this buffer. When you call getchar() and the buffer is empty, the program waits the user to type new string, and hit the Enter. So, when we got EOF from stdin? Basically, never. BUT the user can simulate EOF by type Ctrl+Z. This will enter EOF char, but it have no effect on nothing!. In this case, it is just a char.

Keshan Nageswaran
  • 8,060
  • 3
  • 28
  • 45
yuvalhuck
  • 23
  • 5
  • 1
    EOF is not a char, it's a macro... for further information see [link](http://stackoverflow.com/questions/12389518/representing-eof-in-c-code) – 360NS Jan 21 '17 at 17:43
  • and honestly your answer isn't about my question.. If you didn't understand something please go through the question again (BTW, thanks for the reply :) ) – 360NS Jan 21 '17 at 17:45
  • I find this answer correct and fairly well explained, especially when saying that EOF is a special thing in console. – linuxfan says Reinstate Monica Jan 21 '17 at 18:08
  • i agree it's a special thing, but this doesn't answer nor explain why you'd get the results you'd get if you tried the code i posted in the question – 360NS Jan 21 '17 at 18:32
  • 1
    ...ah, and EOF can really be a character (and it was, for example in the CP/M days). See here: https://en.wikipedia.org/wiki/End-of-file – linuxfan says Reinstate Monica Jan 21 '17 at 18:32
  • @linuxfan yes it's true and i quote the link: "The actual value of EOF is system-dependent (but is commonly -1, such as in glibc") and i mentionned in THE BEGINNING of this question that i'm using GCC compiler.. this is not the question though but thnks anyway – 360NS Jan 21 '17 at 18:37
  • And so? In windows console a ^Z triggers an EOF - doesn't matter what you language/compiler/interpreter is, or how it shows EOF to the program. So who cares about GCC. Laszlo answer is correct, and the one above too, but you mistreated the answerer. – linuxfan says Reinstate Monica Jan 21 '17 at 18:41
  • No @user7427260, I don't think that "you are here to mistreat answerers". I said you mistreated the answerer: it can happen to anyone. You mistreated him with two comments, only because you didn't understand his answer. I instead did understand, and, while it was not perfectly explained, it was a valid answer. Understanding answers requires the same effort, if not more, than understanding questions. English does not help us, but modesty and respect do. Have a nice day. – linuxfan says Reinstate Monica Jan 22 '17 at 08:32
1

You use Ctrl-Z to signal EOF. Your program behaves accordingly. But stdin will remain open. You can still 'close' stdin, but for your program only. Try this, and see the difference:

   while ((c = getchar()) != EOF)
      printf("%c", c);
   fclose(stdin); // <----------
   printf("Let's just check if we can still read from stdin, type a char: ");
   c = getchar();
   printf("\nYou entered: %c\n", c);

You will not get 'a' anymore, you will get EOF (-1).


Edit:

  • EOF is a macro definition in stdio.h, and is commonly equal to -1
  • To simulate EOF via terminal input, type the sequence: Enter-Cntrl-Z-Enter in the Windows console.
  • After EOF signal, the input stream remains open... Why? Because stdin is supposed to be always open. (One could use fclose(stdin) to close the stream, but that is a bad idea, since file handles can easily get messed up.)
  • ^Z is not EOF, if you check for it's value it's 26 (Not -1).
  • Typing ^Z anywhere would flush stdin after that...
Laszlo
  • 769
  • 9
  • 19
  • 1
    thanks for the reply i'm aware of fclose() however, EOF as the very term implies "End Of File" should've worked. It works for some folks under linux and based on answers to this [question](http://stackoverflow.com/questions/288062/is-close-fclose-on-stdin-guaranteed-to-be-correct) fclose(stdin) is a bad idea – 360NS Jan 21 '17 at 17:55
  • 1
    Sure it is. I thought you want to understand how it works. :) Also, pls check how signals work. When you type ^Z , EOF is *signalled*. – Laszlo Jan 21 '17 at 18:07
  • ok will do, btw when EOF is signalled what happens next? like i said in the first comment as the very term implies and according to the answer to this [question](http://stackoverflow.com/questions/1622092/problem-with-eof-in-c) there should be no more input read... – 360NS Jan 21 '17 at 18:27
  • 1
    To show `c` has the value of -1, better to use `printf("\nYou entered: %d\n", c);` (%d) – chux - Reinstate Monica Jan 21 '17 at 18:27
  • @user7427260: When EOF is signalled getchar() returns. When getchar() returns EOF, it means that EOF was signalled, or an error occured. See here: http://www.cplusplus.com/reference/cstdio/getchar/ – Laszlo Jan 21 '17 at 18:37
  • @Laszlo i agree, this behaviour is related to getchar().. However, my question is about the consequences and the behaviour of EOF related to stdin... – 360NS Jan 21 '17 at 18:43
  • 1
    @user7427260 I don't get it. EOF is a condition, a state, a piece of data, a code. It does not have any behavior. getchar() is a function, and as such, it has behavior. – Laszlo Jan 21 '17 at 18:49
  • @Laszlo sorry maybe i wasn't clear enough, what i mean is what happens to the standard input after an EOF has been signalled? thnks for bearing with me :) – 360NS Jan 21 '17 at 18:56
  • 1
    @user7427260 The standard input remains open. – Laszlo Jan 21 '17 at 19:11
  • @Laszlo ok got that! what do you think about the second case: when we type ^Z in the middle of a string, what could explain what happens? – 360NS Jan 21 '17 at 19:24
  • @user7427260 getchar() will not terminate if ^Z is not the first character within the input buffer. In that case it will consider ^Z to be part of the stream. The output will be however truncated to "Hello wor^Z" for "Hello wor^Zld!" by the display output routine, that echoes back the input string. (The last character you see is the actual value of ^Z (26) displayed according to the code page of your DOS box.) – Laszlo Jan 21 '17 at 19:59
  • @Laszlo Ok great! Just one last question: are those characters after ^Z still remain in the buffer? are they flushed? And when you said getchar() will not terminate, do you mean that ^Z acts like '\0' (it stops read) except when it's done on a newline getchar() returns EOF? – 360NS Jan 21 '17 at 20:14
  • @user7427260 Sorry, I mean the while loop will not terminate, because getchar() will return 26, and not -1. And yes, as you say, the input buffer gets flushed after ^Z, so getchar() will continue to wait for input after processing ^Z in "Hello wor^Zld!". – Laszlo Jan 22 '17 at 00:04
  • *Correction*: The output buffer, and printf() is not involved at all, so please disregard that part of my previous comment. In fact one can printf("Hello Wo\032rld!"); and then the output will be: "Hello Wo->rld!" – Laszlo Jan 22 '17 at 00:06
  • @Laszlo thank you! i'll try to work the comments and append them to your answer since i'll accept it, this way if somebody out there is having the same problem, this would help.. thanks again :) – 360NS Jan 22 '17 at 12:47