Unfortunately, the C standard library does not offer any easy way to read a floating-point number from the user, and to automatically keep asking the user until the input is valid. However, you can write such a function yourself, using the functions fgets
and strtof
.
In the code snippet below, I wrote a variadic function
float get_float_from_user( const char *prompt, ... )
which you can call like printf
to print a string. It will repeatedly prompt the user for input using this string, until the input is valid. Once the input is valid, the function will return the user input converted to a float
. You can call the function for example like this:
sub_marks = get_float_from_user( "Enter Marks of Subject %d: ", i );
If you replace the call to scanf
with the line above, then your program should work as desired, after additionally fixing the following bug:
You must initialize temp
to 0
. The line
float sub_marks, total_marks, temp, check = 0;
will not initialize temp
to 0
. It will only initialize check
to 0
. If you want to initialize all 4 variables to 0
, then you should instead write the following:
float sub_marks = 0, total_marks = 0, temp = 0, check = 0;
However, it would probably be better to change the name of temp
to sum
, as that describes the purpose of the variable better. Also you are not using the variables total_marks
and check
at all, so you can remove them. Therefore, you may want to change that line to the following:
float sub_marks, sum = 0;
Note that I am deliberately not initializing sub_marks
, as that is not necessary (initializing sum
is necessary, though).
However, since you are not using sub_marks
outside the loop, it would probably be better to declare it inside the loop, in order to limit its scope.
Also, changing the loop counter i
inside the loop is considered bad programming practice. A cleaner solution would be to create an additional loop inside the loop, so that the inner loop will only stop when the input is in the desired range.
Here is the code which does everything mentioned above:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
float get_float_from_user( const char *prompt, ... )
{
for (;;) //loop forever until user enters a valid number
{
char buffer[1024], *p;
float f;
va_list vl;
//prompt user for input
va_start( vl, prompt );
vprintf( prompt, vl );
va_end( vl );
//get one line of input from input stream
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "unrecoverable error reading from input\n" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "line input was too long!\n" );
//discard remainder of line
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "unrecoverable error reading from input\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
//attempt to convert string to number
errno = 0;
f = strtof( buffer, &p );
if ( p == buffer )
{
printf( "error converting string to number\n" );
continue;
}
//make sure that no range error occurred
if ( errno == ERANGE )
{
printf( "number out of range error\n" );
continue;
}
//make sure that remainder of line contains only whitespace,
//so that input such as "6sdfh4q" gets rejected
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "unexpected input encountered!\n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto continue_outer_loop;
}
}
return f;
continue_outer_loop:
continue;
}
}
int main()
{
float sum = 0;
printf( "\nProgram to add marks of four subjects and to calculate average.\n\n" );
for ( int i = 1; i <= 4; i++ )
{
float sub_marks;
//loop forever until input is in the desired range
for (;;)
{
sub_marks = get_float_from_user( "Enter marks of subject %d: ", i );
if ( sub_marks < 0.0 )
{
printf( "Marks cannot be negative!\n" );
continue;
}
if ( sub_marks > 100.0 )
{
printf( "Marks cannot be greater than 100!\n" );
continue;
}
//input is in acceptable range, so break out of infinite loop
break;
}
sum += sub_marks;
}
printf( "\n" );
printf( "Total marks: 400\n" );
printf( "Obtained marks: %.2f\n", sum);
printf( "Average: %.2f%%\n", sum / 4.0 );
printf( "\n" );
return 0;
}
The program above has the following behavior:
Program to add marks of four subjects and to calculate average.
Enter marks of subject 1: This is a test.
error converting string to number
Enter marks of subject 1: 70
Enter marks of subject 2: 80abc
unexpected input encountered!
Enter marks of subject 2: 80
Enter marks of subject 3: 110
Marks cannot be greater than 100!
Enter marks of subject 3: 90.7
Enter marks of subject 4: abc85
error converting string to number
Enter marks of subject 4: 85
Total marks: 400
Obtained marks: 325.70
Average: 81.43%
The function get_float_from_user
is a slight modification of my function get_int_from_user
from the second code snippet of this answer of mine to another question.