Search code examples
cwhile-loopeofgetchar

Why do I need to include EOF in my loop condition?


I have been given a task to write a program that will take keyboard input (excluding space) and print to a .txt file without using an array.

I tried to use a while loop to do this but was getting an infinite loop, I then came on to stack overflow and found a solution within a different problem, EUREKA!

Adding:

&& ch != EOF 

solved my problem.

However, I do not fully understand why the solution works and would like help to understand why this second condition was needed.

while((ch=getchar()) != '\n' && ch != EOF)
   {
       putc(ch, fin);
   }
   fclose(fin);
   return 0;

Thank you.


Solution

  • Because the return value of getchar is the character read on success, and EOF on error or when the end-of-file has been reached:

    man getchar

    RETURN VALUE

    fgetc(), getc() and getchar() return the character read as an unsigned char cast to an int or EOF on end of file or error.

    There are several reasons as to why stdin might reach end-of-file:

    • The user pressed Ctrl+D (on Unix/Linux) which causes stdin to close
    • stdin was connected to a pipe ($ cat file.txt | ./myprogram) and the pipe closed because cat ended.
    • stdin was connected to a redirection ($ ./myprogram < file.txt) and it reached the end of file.txt

    On all this cases, getchar will eventually return EOF and you cannot keep reading. If you do

    while((ch=getchar()) != '\n')
    {
        ...
    }
    

    and stdin closes, then you end up in an endless loop, als EOF != '\n' always evaluates to true. So in order to protect yourself from that, you have to check if the read operation failed. And you do that by checking whether the reading function returned EOF. That's why

    int ch;
    while((ch=getchar()) != '\n' && ch != EOF)
    {
        ...
    }
    

    is the correct way of looping with getchar. Also note that ch must be of type int.

    Note also that this applies for all FILE buffers (opened in read mode), not only to stdin.