1

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
--

Rune
  • 13
  • 5
  • 1
    instead of `scanf` I'd use get `getchar` to read user input; then you have a single char that you can check for a digit. – Oliver Mason Jun 10 '20 at 11:15
  • As far as `scanf("%d"...)` is concerned, `02` is a valid integer as is `2` and they have the same value. Also, `2a` will read the `2`. If you want this to be more exact, read the input as a single character since a leading 0, for example, is going to be part of a valid integer input for any of the integer parsing functions in the C library. – lurker Jun 10 '20 at 11:15
  • 2
    Initialising all vairables is a habit you should adopt. – RubberBee Jun 10 '20 at 11:18

2 Answers2

1

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;
}
user3121023
  • 8,181
  • 5
  • 18
  • 16
0

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' );
}
user3629249
  • 16,402
  • 1
  • 16
  • 17