Control user input in C when there is chars and ints mixed

256 views Asked by At

So I'm trying making a simple menu to a program that only accepts the options 1,2 and 3 and I want to control the user input to prevent errors like when the user inputs char instead of int.

Right now it controls some cases like if the option is less than 1 or greater than 3, if the option is a char it also does not affect but when the user inputs something like " 02" or "2a" it runs option 2 but should invalidate that option.

Also if there“s more cases that I'm missing I would like to know them and how to overcome them.

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

void empty_stdin(void);

int main() {
    int option;
    int rtn;

    do {
        printf("\n--\nOptions:\n1.Option 1\n2.Option 2\n3.Option 3\n--\n\nPlease chose option (1/2/3) to continue: ");
        rtn = scanf("%d", &option);

        if (rtn == 0 || option < 1 || option > 3) {
            printf("-Invalid Option-\n");
            empty_stdin();
        } else {

            empty_stdin();

            switch (option) {
                case 1:
                    printf("Option 1");
                    break;

                case 2:
                    printf("Option 2");
                    break;
                case 3:
                    printf("Option 3");
                    exit(0);

                default:
                    printf("\n-Invalid Option-\n");
            }
        }
    } while (option != 3);
    return 0;
}

void empty_stdin(void) {
    int c = getchar();

    while (c != '\n' && c != EOF)
        c = getchar();
}

Example Input/Output

--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 1
Option 1
--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 12
-Invalid Option-

--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: char
-Invalid Option-

--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 02
Option 2
--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 2a
Option 2
--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 02a
Option 2
--
Options:
1.Option 1
2.Option 2
3.Option 3
-- 

Expected Input/Output

--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 1
Option 1
--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 12
-Invalid Option-

--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: char
-Invalid Option-

--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 02
-Invalid Option-
--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 2a
-Invalid Option-
--
Options:
1.Option 1
2.Option 2
3.Option 3
--

Please chose option (1/2/3) to continue: 02a
-Invalid Option-
--
Options:
1.Option 1
2.Option 2
3.Option 3
--

2

There are 2 answers

0
user3121023 On BEST ANSWER

Consider using fgets to capture input and strtol to parse an integer.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

int fgetsint ( int *value, int min, int max, FILE *fin) {
    char line[100] = "";
    char extra = '\0';
    char *end = NULL;
    long int number = 0;

    if ( fgets ( line, sizeof line, fin)) {//read a line
        errno = 0;
        number = strtol ( line, &end, 10);
        if ( end == line) {// nothing was parsed. no digits
            printf ( "input [%s] MUST be a number\n", line);
            return 0;// return failure
        }
        if ( ( errno == ERANGE && ( number == LONG_MAX || number == LONG_MIN))
        || ( errno != 0 && number == 0)) {// parsing error from strtol
            perror ( "input error");
            return 0;
        }
        if ( 1 == sscanf ( end, " %c", &extra)) {//parse trailing character
            printf ( "enter one number only. try again\n");
            return 0;
        }
        if ( number > max || number < min) {
            printf ( "Input [%ld] out of range: min: %d max: %d\n", number, min, max);
            return 0;
        }
        if ( 1 != (int)( end - line)) {
            printf ( "input one digit\n");
            return 0;// return failure
        }
        *value = number;//assign number to pointer
    }
    else {
        fprintf ( stderr, "problem fgets\n");
        exit ( EXIT_FAILURE);
    }

    return 1;//success
}

int main ( void) {
    int option = 0;

    do {
        printf("\n--\nOptions:\n1.Option 1\n2.Option 2\n3.Option 3\n--\n\nPlease chose option (1/2/3) to continue: ");

        option = 0;
        fgetsint ( &option, 1, 3, stdin);

        switch (option) {
            case 1:
                printf("Option 1");
                break;

            case 2:
                printf("Option 2");
                break;
            case 3:
                printf("Option 3");
                exit(0);

            default:
                printf("\n-Invalid Option-\n");
        }
    } while ( option != 3);
    return 0;
}
0
user3629249 On

The following proposed code:

  1. cleanly compiles
  2. performs the desired functionality
  3. handles all the 'oops' cases
  4. honors the right margin, for printing, etc

and now, the proposed code:

#include <stdio.h>

void empty_stdin( void );

int main( void ) 
{
    int option = 9;

    do 
    {
        printf("\n--\nOptions:\n"
               "1.Option 1\n"
               "2.Option 2\n"
               "3.Option 3\n"
               "--\n\n"
               "Please chose option (1/2/3) to continue: ");
        option = getchar();

        empty_stdin();

        switch (option) 
        {
            case 1:
                printf( "Option 1\n" );
                break;

            case 2:
                printf( "Option 2\n" );
                break;

            case 3:
                printf( "Option 3, exiting\n" );
                //exit(0);
                break;

            default:
                printf( "\n-option: %d invalid-\n", option );
                break;
        }
    } while ( option != 3 && option != EOF );
    return 0;
}

void empty_stdin( void ) 
{
    //int c = getchar();

    //while (c != '\n' && c != EOF)
        //c = getchar();
    int c;
    while( (c = getchar() ) != EOF && c != '\n' );
}