I have a program that is supposed to get input from a user until it receives EOF.
\n or white spaces are considered as legal chars,
but the console recognizes neither ^z nor ^d as EOF and the program continues to run until stopped manually.
Tried both:
while (currChar != EOF)
{
scanf("%c", &currChar);
}
and:
scanf("%c", &currChar);
if (currChar==EOF)
break;
scanf() doesn't set the variable to EOF when it gets to the end of the input, it returns EOF. So you have to test the value of the function.
while (scanf("%c", &currChar) != EOF) {
...
}
Well, EOF is not a character. It's an integer constant with the value of -1. With that said if you enter with the value of EOF, your char variable would read only the - (minus) from -1 value. That's why the loop won't stop, they'll never be equal.
Related
I was trying to make a code that gets only an integer as input. I found a working solution here
int n, input, temp, status;
printf("Height:");
status = scanf("%d",&n);
while(status!=1)
{
while((temp=getchar()) != EOF && temp != '\n');
printf("Height:");
status = scanf("%d", &n);
}
I want to know what exactly makes this part work and what are those "extra hidden characters"
while((temp=getchar()) != EOF && temp != '\n');
Can anyone explain, please?
while((temp=getchar()) != EOF && temp != '\n');
First, you need to understand what getchar function does, namely:
The C library function int getchar(void) gets a character (an unsigned
char) from stdin.
Return Value
This function returns the character read as an unsigned char cast to an int or > EOF on end of file or error.
When the user types something that will be picked by the scanf, the user press an [enter] which will send a "\n". That newline will not be read by the scanf function but rather stay on the input buffer. The EOF is for the case that someone explicitly closes the stream, for instance pressing CTRL-Z. So the code:
while(status!=1)
{
while((temp=getchar()) != EOF && temp != '\n');
printf("Height:");
status = scanf("%d", &n);
}
check first the returning type value of the scanf which:
Return Value On success, the function returns the number of items of
the argument list successfully read. If a reading error happens or the
end-of-file is reached while reading, the proper indicator is set
(feof or ferror) and, if either happens before any data could be
successfully read, EOF is returned.
In your case, you expect to read a single numerical value (i.e., status = scanf("%d",&n);). The remains of the loop is basically asking for the user to provide a valid input (i.e., a numeric value), which consequently leads to status being 1, and the exit of the outermost while loop.
If a user enters some non-numeric input (for example foo instead of an integer) then scanf will return 0 and leave the non-numeric input in the input buffer.
So the next time you call scanf it will attempt to read the exact same non-numeric input and fail again.
The loop
while((temp=getchar()) != EOF && temp != '\n');
will read character by character until either it comes to and end of file, or the character is a newline. The characters the loop reads will be ignored and thrown away.
This is a way to skip all the non-numeric input that the user might have entered.
The EOF character is received when there is no more input. The name makes more sense in the case where the input is being read from a real file, rather than user input (which is a special case of a file).
This means that your loop will break when you receive an EOF or if the user hits enter, in this case, you receive a '\n'.
I wrote a simple program to test the scanf() function in C. It basically reads from the terminal, char by char, reprinting the return value and the char read; and to terminate if EOF/EOT is met or if a \n newline is read.
#include <stdio.h>
#include <stdbool.h>
int main(void) {
char c; int ret;
printf("Enter the chars to test: ");
//LOOP (scan & print) only when return is not EOF and char is not newline
while ( ((ret = scanf("%c", &c)) != EOF) && c!='\n' ) {
printf("%i %c\n", ret, c);
}
return 0;
}
It terminates correctly, if newline (Enter) is pressed. But the it won't just terminate with a single Ctrl-D. A single Ctrl-D will flush the typed 'chars' and printing them. Then after that it will wait again for input, although an EOF has been sent with the Ctrl-D. If we press Ctrl-D again the 2nd time directly after the 1st (2x) or just Enter it will terminate. So you will need two consecutive Ctrl-D to terminate the program (or the loop in this case).
Example:
If you input 987 on the terminal, then press Enter; then 1 9, 1 8, 1 7 will be printed on newline each.
If you input 987 on the terminal, then press Ctrl-D; then 1 9 will be printed on the same line (because there is no Enter typed after inputing the 987 input), 1 8, 1 7 will be printed on newline. Then it will still wait for more inputs, unless it is terminated by directly entering a 2nd consecutive Ctrl-D or with a newline (Enter). So it (the program) will only stop (exit the loop) after a newline or 2nd consecutive Ctrl-D.
I am confused. Shouldn't a single Ctrl-D sent stop the loop here? What should I do to stop the program (scanf loop) after receiving just a single Ctrl-D?
I tested the code on Lubuntu 19.10 with gcc 9.2.1.
The issue is scanf() does not return EOF until there is no more input waiting and EOF is encountered. (your "%c" conversion specifier will otherwise accept any character, including the '\n' character, as valid and consider it a successful conversion)
When you type a line of characters, e.g. "abcdefg" and attempt to press Ctrl+d (indicating end-of-input), the input ("abcdefg") is processed and when 'g' is reached, then scanf() blocks waiting on your next input. (because a successful conversion took place and no matching or input failure occurred)
Once Ctrl+d is typed a 2nd time (indicating end-of-input), when there is no input to process, EOF is reached before the first successful conversion and an input-failure occurs,scanf() then returns EOF.
See: man 3 scanf -- RETURN VALUE section and C11 Standard - 7.21.6.2 The fscanf function(p16)
Test the returned value for one, not EOF. When eof is reached first time, zero is returned. The next scanf after zero returns EOF.
while ( ((ret = scanf("%c", &c)) == 1) && c!='\n' ) {
printf("%i %c\n", ret, c);
}
This behavior is specified for the standard C library.
On success, the function returns the number of items of the argument list successfully filled. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.
If a reading error happens or the end-of-file is reached while reading, the proper indicator is set (feof or ferror).
You can add if (feof(stdin) != 0) break; into the loop body, if you use more complex input format.
If you read chars only, is it not better use fgetc?
Output
Code:
#include<stdio.h>
main()
{
int c;
printf("Enter any charachter!: ");
while((c = getchar()) != EOF) {
putchar(c);
printf("%d\n", (c = getchar()) != EOF);
}
}
I've tried to test out EOF in C and I'm having a difficult time with it. I've wanted to get the value of EOF and found out that it is -1.
I wrote a simple program using getchar() and putchar().
I have added the screenshot of the program and output. Output doesn't make any sense to me.
As you can see I'm trying to get a character and display it using getchar() and putchar(). And I'm trying to print out the value of the condition used in the while loop. To check the EOF I'm deliberately entering -1 as input. putchar() prints out -1 and then the final printf statement confuses me. I enter -1 for getchar() but 1 displayed meaning c is not equal to EOF. But I thought -1 is EOF.
And I don't understand why 11 is also displayed. I'm using codeblocks IDE.
Please help me. Thanks in advance.
EOF isn’t a character, and it isn’t read from the stream. It’s just the return value indicating that there is no more input on that stream. You can signal an EOF by typing CtrlD on *nix or CtrlZ on Windows.
getchar takes input one character(byte) at a time. so when you input '-1' it is treated as a character array input and first getchar takes input only '-' and second one takes input '1'. Thus you are not getting your desired output. Also putchar is designed to print one character at a time. So it might not work properly too. You can change your code following way to make it work.
int c;
while(scanf("%d", &c)!=EOF) { //to ensure there is some input value as scanf will return EOF when input stream finishes.
printf("%d\n", c);
if(c == EOF) {
printf("c is equal to EOF\n");
break;
}
}
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!
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...
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.
I have the following for loop, I am prompting the user to enter a 4 digit pin and hit enter. Can someone explain to me what the while loop is really doing because I don't fully understand it.
//user input for pin
for(i = 0; i < PIN_LENGTH; i++)
{
printf("Enter digit %d of your PIN: ", i);
user_pin[i] = getchar();
while (getchar() != '\n'); //what is this line doing??
}
As mentioned by others, this loop discards unwanted characters from stdin so that the next input function has a clean stream, and in particular it discards the \n that follows the last character entered by the user. But, getchar() returns EOF in the event of a read error, so the loop should test for EOF also, like this:
int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
continue; // discard unwanted characters
Also note that, if stdin has been redirected, it is possible to reach EOF without encountering a \n. And, as #chqrlie pointed out in the comments, the user can signal an EOF from the terminal by entering Ctrl-D in Linux, or Ctrl-Z in Windows. Hence the importance of testing for EOF explicitly.
When you give input to the program, then you end it with the Enter key. This key is sent to your program as a newline.
What the loop does is to read and discard characters until it has read the newline. It flushes the input buffer.
If you don't do this, then the next main getchar call would return the newline instead of the digit you expect.
The next line is discarding the possible extra chars that the user may have inputted, and also the linefeed char that the user had to input.
So other scanf/getchar methods further in the code are not polluted by this spurious input.
The while loop is used to check when the user will press enter.Enter is considered as '\n'.
That line is a while, so at run-time it will repeat it until getchar() == '\n'. '\n' is a character that in ASCII means "enter" key. In this way you can test that the user will not press "enter" without had inserted a number.
**The function of this while loop is to clear the users' illegal input .When the input is '\n' ,the loop ends.