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'.
Related
I have a piece a code that works for input validation, I need a little bit more explanation for why it works. The line where the garbage variable reads a character from getchar and checks to see if it's not equal EOF confuses me a little. It's purpose is to read the garbage input from the user, and allow the user to re-enter the input. My question is, how exactly does this line work?
int steps = 0;
int true;
int garbage;
printf("Enter the integer increment number in the range ");
printf("of[%d - %d]: ", minInput, maxInput);
true = scanf("%d", &steps);
/* INPUT VALIDATION */
while (!true || isdigit(steps) ||(steps < minInput || steps > maxInput) ){
while ((garbage = getchar()) != EOF && garbage != '\n') {
} // end while;
printf("Invalid input... please enter a number in the range ");
printf("of[%d - %d]: ", minInput, maxInput);
true = scanf("%d", &steps);
}// end while
The scanf() call with the %d format specifier will retrieve only decimal digit characters, and will stop interpreting input at the first non-digit character. However it will not normally return at all until a complete line is buffered, so there will be at least a newline buffered and possibly other non-digit characters.
The:
while ((garbage = getchar()) != EOF && garbage != '\n')
statement reads all buffered characters until the end of the line or EOF. While it is perhaps unusual for the console input stream to issue an "end-of-file", the stdin stream can be redirected from a file and need not refer to the console input. An EOF may be inserted into the console input stream via a platform dependent CTRL code, and when redirected from a file, if the file contained a line without a newline, the loop would not terminate.
The use of isdigit(steps) is incorrect - steps is an integer value and isdigit() tests a single character value to determine whether it represents a decimal digit. steps is implicitly a valid value by virtue of the true being non-zero and the %d format specifier, so if the intent is to determine a number was entered that is what true is for.
I have been trying to understand how EOF works. In my code (on Windows) invoking EOF (Ctrl+Z and Enter) doesn't work the first time and I have to provide two EOF for it to actually stop reading input. Also, the first EOF gets read as some garbage character which gets displayed when I print the input. (We can see the garbage characters being display at the end in the output provided).
This is my code:-
#include<stdio.h>
#define Max 1000
int main()
{
char c, text[Max];
int i = 0;
while((c = getchar()) != EOF)
{
text[i] = c;
i++;
}
printf("\nEntered Text: \n");
puts(text);
return 0;
}
My Output:
I have this doubt:-
Why are two EOFs being required? and how do I prevent the first one from being read (as some garbage) and stored as part of my input?
Control-Z is only recognized as EOF when at the start of a new line. Therefore, if you want to detect it in the middle of a line, you'll need to do so yourself.
So change this line:
while((c = getchar()) != EOF)
to this:
while((c = getchar()) != EOF && c != CTRL_Z)
and then add:
#define CTRL_Z ('Z' & 0x1f)
at the top of your program.
You may still need to type a return after the Ctrl-z to get the buffered input to be read by the program, but it should discard everything after the ^Z.
The following solution fixes the Ctrl+Z problem and the garbage output and also blocks a buffer overrun. I have commented the changes:
#include <stdio.h>
#define Max 1000
#define CTRL_Z 26 // Ctrl+Z is ASCII/ANSI 26
int main()
{
int c ; // getchar() returns int
char text[Max + 1] ; // +1 to acommodate terminating nul
int i = 0;
while( i < Max && // Bounds check
(c = getchar()) != EOF &&
c != CTRL_Z ) // Check for ^Z when not start of input buffer
{
text[i] = c;
i++;
}
text[i] = 0 ; // Terminate string after last added character
printf( "\nEntered Text:\n" );
puts( text );
return 0;
}
The reason for this behavior is somewhat arcane, but end-of-file is not the same as Ctrl-Z. The console generates an end-of-file causing getchar() to return EOF (-1) if and only if the console input buffer is empty, otherwise it inserts the ASCII SUB (26) character into the stream. The use of SUB was originally to do with MS-DOS compatibility with the even earlier CP/M operating system. In particular CP/M files were composed of fixed length records, so a ^Z in the middle of a record, was used to indicate the end of valid data for files that were not an exact multiple of the record length. In the console, the SUB is readable rather than generating an EOF if it is not at the start of the input buffer and all characters after the SUB are discarded. It is all a messy hangover from way-back.
Try changing the type of c to int as EOF can be a negative number and commonly it is defined as -1. char might or might not be able to store -1. Also, do not forget to end the string with \0 before passing it to puts.
The logic that Windows terminals follow with regard to ^Z in keyboard input (at least in their default configuration) is as follows:
The Ctrl-Z combination itself does not cause the input line buffer to get pushed to the waiting application. This key combination simply generates ^Z character in the input buffer. You have to press Enter to finish that line buffer and send it to the application.
You can actually keep entering additional characters after ^Z and before pressing Enter.
If the input line does not begin with ^Z, but contains ^Z inside, then the application will receive that line up to and including the first ^Z character (read as \x1A character). The rest of the input is discarded.
E.g. if you type in
Hello^Z World^Z123
and press Enter your C program will actually read Hello\x1A sequence. EOF condition will not arise.
If the input line begins with ^Z, the whole line is discarded and EOF condition is set.
E.g. if you input
^ZHello World
and press Enter your program will read nothing and immediately detect EOF.
This is the behavior you observe in your experiments. Just keep in mind that the result of getchar() should be received into an int variable, not a char variable.
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.
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.
I've just started to learn c programming. I don't know weather this question is silly or not.
Where do i use
while(getchar()! ='\n') ;
When using scanf function in some program the above mentioned while loop is used whereas some other program doesn't use the while loop after the scanf function.
So, where should i use this while loop and where not to?
Use the loop to clean up the rest of a line after an error
You use code similar to the loop in the question when you think there is debris left on a line of input after you (attempted to) read some data from standard input but the operation failed.
For example, if you have:
int n;
if (scanf("%d", &n) != 1)
…recover from error here?…
The error recovery should check for EOF (it is correct to use feof() here — but see while (!feof(file)) is always wrong for how not to use feof()), and if you didn't get EOF, then you probably got a letter or punctuation character instead of a digit, and the loop might be appropriate.
Note that you should always check that the scanf() operations — or any other input operation — succeeded, and the correct check for the scanf() family of functions is to ensure you got the expected number of successful conversions. It is not correct to check whether scanf() returned EOF; you can can get 0 returned when there's a letter in the input queue and you ask for a number.
Beware EOF
Incidentally, the loop in the question is not safe. It should be:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
If the loop in the question gets EOF, it continues to get EOF, and isn't going to do anything useful. Always remember to deal with it. Note the use of int c; too — getchar() returns an int and not a char, despite its name. It has to return an int since it returns every valid character code and also returns a distinct value EOF, and you can't fit 257 values into an 8-bit quantity.
While loop syntax :
while (condition test)
{
// C- statements, which requires repetition.
// Increment (++) or Decrement (--) Operation.
}
while(getchar()! ='\n') ;
Here your condition is getchar()!='\n'.
First getchar() will execute . It will ask input from user. This function returns the character read as an unsigned char cast to an int or EOF on end of file or error. While loop keep continue executing until return value will not match with '\n'
scanf() example : scanf("%s", &str1);
With scanf you can ask user for enter input one time only For more than one input you have to place scanf in loop.
Where as you ask to enter input to user in while loop condition So It will keep asking input from user until EOF signal occur.
When the scanf() format string does not cause it to read the newline from the input buffer.
Most simple format specifiers will not read the newline. However if you use %c, any character may be read, including newline, in which case the loop will need modification:
while( ch != '\n' && getchar() != '\n' ) ;
Where ch is the variable receiving the %c input.
Because console input is normally line-buffered, failing to consume the newline will cause subsequent stdin reading functions to return immediately without waiting for further input, which is seldom what is intended.
You would not use such a loop in cases where multiple fields are entered in a single line but processed in separate scanf() (or other stdin function) calls.