So I started to learn C using the ANSI C book. One of the early exercises in the book is to write a program that takes text input and prints every word on a new line, simple enough. So i did:
#include <stdio.h>
#define IN 1
#define OUT 0
main() {
int c;
int state;
state = OUT;
while((c = getchar()) != EOF){
if(c != ' ' && c != '\n' && c != '\t'){
state = IN;
}else if(state == IN){
state = OUT;
putchar('\n');
}
if(state == IN)
putchar(c);
}
getchar();
}
The thing is that while the program works fine it won't break from the while loop if I enter EOF
(Ctrl+Z on windows) as the last char of a line or in the middle of it.
So I found an answer here.
What I learned is that the (Ctrl+Z) char is some sort of signal to end the stream and it must be on a new line for getchar()
to return EOF
. While this is all good and it kinda helped I really want to know why is it necessary for the EOF
to be on its own line?
The problem you are having is related to your command line terminal and has nothing to do with the end of file marker itself. Instead of sending characters to the program as you type them, most terminals will wait until you finish a whole line before sending what you type to the program.
You can test this by having the input come from a text file instead of being typed by hand. You should be able to end the input file without a newline without any problems.
./myprogram.exe < input.txt
By the way, the answer you linked to also points out that EOF is not a character that is actually in your input stream, so there is no way for it to come "before" a "\n". EOF is just the value that getchar
returns once there are no characters left to be read.
When reading from a tty device (such as stdin for a program running in a console or terminal window) the terminal is in so-called cooked mode. In this mode, some level of line editing facilities are provided, allowing the user to backspace and change what has been typed.
The characters that are typed are not returned to the program until after return has been pressed.
It is possible to do this by placing the terminal in 'raw' mode. Unfortunately it seems this is not well standardised though, so it is somewhat system specific. The answers to this question have some examples for various platforms.