Home > Blockchain >  How to deal with wrong input in C?
How to deal with wrong input in C?

Time:03-29

I am just a beginner to C language. I am trying to write a programme that take marks of four subjects. But in case if user provides a wrong input such as alphabets then it should print "Please Enter Number" and should again ask the marks of same subject.

Here is my code..

// Programme to add marks of four subject and to calculate percentage.
#include <stdio.h>
#include<ctype.h>
int main()
{
    float sub_marks, total_marks, temp, check = 0;

    printf("\nPragramme to add marks of four subject and to calculate percentage.\n\n");
    for (int i = 1; i <= 4; i  )         //Running loop four times to enter marks of four subjects.
    {

        printf("Enter Marks of Subject %d: ", i);
        scanf("%f", &sub_marks);

        if (sub_marks > 100)        //condition for what to do if marks are greater then 100
        {
            printf("\n**MARKS CONNOT BE GREATER THEN 100**\n\n");
            i--;
        }

        else
        {
            temp = temp   sub_marks;    //addind marks to get total marks
        }
    }

    printf("\n\nTotal Marks: 400");
    printf("\n\nObtained marks: %.2f", temp);
    printf("\n\nPercentage: %.2f%%\n\n", temp / 4);
    return 0;
}

I did try a lot but ended up with output..

Pragrame to add marks of fout subject and to calculate percentage.

Enter Marks of Subject 1: 65
Enter Marks of Subject 2: y

**PLEASE ENTER NUMBER.**

Enter Marks of Subject 3: 
**PLEASE ENTER NUMBER.**

Enter Marks of Subject 4: 
**PLEASE ENTER NUMBER.**

After entering alphabet it dosen't let the user to input for the rest of the loops. Instead it should ask "Enter Marks of Subject 1:"

I achived above output by placing below code after else.

 while (sub_marks >= 0)
        {

            remainder = sub_marks % 10;
            if (!isdigit(remainder))
            {
                printf("Please enter Number");
                break;
            }
        }

CodePudding user response:

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.

CodePudding user response:

I've tried to put everything together as much as possible, but it's hard to read input correctly, managing everything that users can throw at you. This version is not perfect!

The main thing is that you were computing the "average", not the "percentage".

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int main(void)
{
    printf("Program to add marks of four subjects and to calculate the average.\n\n");
    float total_marks = 0;
    for (int i = 1; i <= 4; i  ) { // Running loop four times to enter marks of four subjects.
        bool valid = false;
        while (!valid) {
            printf("Enter mark of subject %d: ", i);
            char line[256];
            if (fgets(line, 256, stdin) == NULL) {
                printf("\n**INPUT ERROR OR EOF**\n\n");
                exit(EXIT_FAILURE);
            }
            
            float mark;
            int n;
            if (sscanf(line, "%f %n", &mark, &n) != 1) {
                printf("\n**ENTER A FLOATING POINT VALUE**\n\n");
            }
            else if (line[n] != 0) {
                printf("\n**DON'T ADD ANYTHING AFTER THE NUMBER**\n\n");
            }
            else if (mark < 0 || mark > 100) {
                printf("\n**MARKS MUST BE BETWEEN 0 AND 100**\n\n");
            }
            else {
                valid = true;
                total_marks  = mark; // add marks to get total
            }
        }
    }

    printf("Total Marks: %.2f\n", total_marks);
    printf("Average: %.2f\n\n", total_marks / 4);
    
    return EXIT_SUCCESS;
}
  •  Tags:  
  • c
  • Related