The problem with using scanf
is that it treats all whitespace characters (e.g. spaces and newline characters) as equal. For example, scanf
won't care whether the numbers you entered are on the same line or not.
If scanf
is asked to read two numbers, but the user instead enters three numbers on the same line, then your first call to scanf
will only read the first two numbers and leave the third number on the input stream, so that the next scanf
call in the next loop iteration will read it as the next first number. This is not what you want.
Therefore, for line-based user input, it is probably better not to use scanf
. Instead, it makes more sense to always read exactly one line per loop iteration. You can do this with the function fgets
.
After using fgets
to read a line of input, two of the other answers use sscanf
to convert both numbers at once. However, you can also convert one number at a time using strtof
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <stdbool.h>
int main(void)
{
//we want to provide the user with a different prompt the first time,
//so we must remember whether it is the first time
bool first = true;
//infinite loop
while ( true )
{
float x, exp;
char line[100];
char *p, *q;
//prompt user for input
if ( first )
{
printf(
"Please enter a number followed by the power "
"you want to raise it to: "
);
//remember to use a different prompt next time
first = false;
}
else
{
printf("Enter the next pair of numbers: ");
}
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
//break out of infinite loop
break;
}
//attempt to find newline character
p = strchr( line, '\n' );
//make sure entire line was read in
if ( p == NULL && !feof(stdin) )
{
//only accept missing newline character on end-of-file
if ( !feof(stdin) )
{
int c;
printf( "Line too long for input buffer!\n" );
//discard remainder of line
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
continue;
}
}
else
{
//remove newline character by overwriting it with null character
*p = '\0';
}
//start parsing at start of line
p = line;
//attempt to convert first number
x = strtof( p, &q );
//determine whether conversion of first number succeeded
if ( p == q )
{
printf( "Conversion of first number failed!\n" );
continue;
}
//continue parsing at end of first number
p = q;
//attempt to convert second number
exp = strtof( p, &q );
//determine whether conversion of second number succeeded
if ( p == q )
{
printf( "Conversion of second number failed!\n" );
continue;
}
//verify that remainder of line is either empty or only
//consists of whitespace characters
for ( p = q; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected character found after second number!\n" );
//we cannot use the "continue" keyword here, because
//we want to continue to the next iteration of the
//outer loop, not the inner loop
goto continue_outer_loop;
}
}
//print result
printf( "Input accepted, the result is: %f\n", pow(x, exp) );
continue_outer_loop:
continue;
}
return 0;
}
This program has the following behavior:
Please enter a number followed by the power you want to raise it to: abc
Conversion of first number failed!
Enter the next pair of numbers: 10
Conversion of second number failed!
Enter the next pair of numbers: 10 abc
Conversion of second number failed!
Enter the next pair of numbers: 10 20
Input accepted, the result is: 100000000000000000000.000000
Enter the next pair of numbers: 10 20 30
Unexpected character found after second number!
As you can see, the program correctly rejects the input if it contains a third number.