Caution: fflush(stdin);
may be undefined behavior. Read: Why fflush(stdin)
is wrong?
int fflush(FILE *ostream);
The ostream
points to an output stream or an update stream in which the
most recent operation was not input, the fflush
function causes any
unwritten data for that stream to be delivered to the host environment
to be written to the file; otherwise, the behavior
is Undefined
.
You can try a loop and read until EOF
or
given this FAQ entry instead of fflush(stdin)
as I have suggested below in my answer.
Edit: thanks to @Jonathan Leffler:
There are platforms where fflush(stdin)
is fully defined (as a non-standard extension on that platform). The primary example is a well-known family of systems known collectively as Windows. Microsoft's specification of int fflush( FILE *stream );
If the stream
is open for input, fflush
clears the contents of the buffer.
I have additional doubt in your code; what is M
in expression unsigned int b = pow(2,M-1);
? It should be an error if you don't define it. Are you posting complete code?
Regarding you logic of error detection:
re-read the value if user enters an invalid
No, scanf()
does not return an error code. It returns the number of successful conversions.
int scanf ( const char * format, ... );
Return Value
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
). And, if either
happens before any data could be successfully read, EOF
is returned.
If an encoding error happens interpreting wide characters, the
function sets errno
to EILSEQ
.
So actually depending on the error encountered the return value may be zero, EOF. You should use int ferror ( FILE * stream );
and errno
macro for error detection (check the example given at link).
Errors possible because of invalid input can be:
EILSEQ
: Input byte sequence does not form a valid character.
EINVAL
: Not enough arguments; or format is NULL.
ERANGE
: An integer conversion would exceed the size that can be stored in the corresponding integer type.
Check scanf manual for complete list.
Reason for infinite loop:
The system keeps track of which input has been seen so far. Every call to scanf
picks up from where the last one stopped matching input. This means that if an error occurred with the previous scanf
, the input it failed to match is still left unread, as if the user typed ahead. If care isn't taken to discard error input, and a loop is used to read the input, your program can get caught in an infinite loop.
So for example in your code:
x = scanf("%u", &a);
// ^
// need a number to be input
But suppose you don't input a number but an invalid string is entered e.g. "name"
(instead of a number, as you say). This will cause the scanf()
function to be fail when attempting to match an unsigned integer ("%u"
), and the word "name"
is left unread. So the next time through the loop, the scanf()
doesn't wait for fresh user input, it tries to convert "name" again.
Similarly if the input were 29.67
, the "%u
" will match the first two characters only (the 29
), leaving the .67
as unread input for the next call to scanf()
.
Even if the input is correct, as 29
, the newline that ended the input is still left unread. Normally that isn't a problem since most conversions automatically skip leading white-space such as the trailing newline from the previous line. However some conversions ("%c"
and "%["
) don't skip any leading white-space, so you have to do it manually.
To avoid this infinite-loop One suggestion:
(remember: as I recommended the use of ferror()
, error-value is preferable to detect invalid input. Additionally, it's just for learning purpose and if you need to implement a serious application you should use fgets(str)
instead of scanf()
followed by that parse str
input to verify whether input is valid)
input:
//fflush(stdout); //use if needed, as
used in printf no need of fflush-stdout
printf("
Enter any integer: ");
x = scanf("%u", &a); // always wait for new symbols
printf("%u", a);
if(x == 0){ // x=0, if error occurred
// read all unread chars
while ((ch = getchar()) != '
' && ch != EOF);
goto input;
}
It's just a suggestion that will possibly work with your code (worked for me, your code + gcc). But if you use this technique incorrectly it may leave a bug in your code:
Read How do I flush the input buffer?
If you are sure that unwanted data is in the input stream, you can use
some of the following code snippets to remove them. However, if you
call these when there is no data in the input stream, the program will
wait until there is, which gives you undesirable results.