The %f
conversion specifier tells scanf
to stop reading input as soon as it sees a character that isn't part of a legal floating-point constant (i.e., something that isn't a digit, decimal point, or sign). That bad character gets left in the input stream, so the next call to scanf
fails, and the next, and the next, etc.
You should always check the return value of scanf
- it will tell you how many items were successfully read and assigned from the input stream. In this case, you're expecting a single item, so you should get a return value of 1. If you get a return value of 0, then it means the input is not a proper floating point value, and that bad input has to be cleared somehow. Here's one possible solution:
if ( scanf( "%f", &minutes ) == 1 )
{
// process minutes as normal
}
else
{
// clear everything up to the next whitespace character
while ( !isspace( getchar() ) )
; // empty loop
}
The only problem with this is that scanf
is kind of dumb, and if you type something like 123fgh
, it will convert and assign the 123
while leaving fgh
in the input stream; you would probably want to reject that whole input completely.
One solution is to read the input as text, and then convert it using strtod
:
char buffer[BUFSIZE]; // where BUFSIZE is large enough to handle expected input
...
if ( fgets( buffer, sizeof buffer, stdin ) )
{
char *chk; // chk will point to the first character *not* converted; if
// it's anything other than whitespace or the string terminator,
// then the input was not a valid floating-point value.
double tmp = strtod( buffer, &chk );
if ( isspace( *chk ) || *chk == 0 )
{
minutes = tmp;
}
else
{
// input was not a proper floating point value
}
}
This has the benefit of not leaving crap in the input stream.