Home > OS >  How to detect non-integer input in C
How to detect non-integer input in C

Time:12-30

I have this program:

#include <stdio.h>

int main(){
    int val;
    printf("Enter any number: ");
    scanf("%d",&val);
    printf("The number incremented is %d\n",val 1);
    printf("Enter any number again: ");
    scanf("%d",&val);
    printf("The number decremented is: %d\n",val-1);
    return 0;
}

It works completely fine if i give it an integer input, but when its a different input, the program goes crazy and runs without accepting the second input. (the second output is -1). is there a fix to this?

I have tried to test the program with number and non-number inputs, For the non number one in the first input, as the description said, the program continued and didnt accept the second input.

Edit: I did not mention the desired output of the program, sorry about that. If the output is non-integer then it will return with err code 1.

CodePudding user response:

If you want the function to return -1; in the case of the user entering invalid input, then you should check the return value of scanf, for example like this:

#include <stdio.h>

int main( void )
{
    int val;

    printf( "Enter any number: ");
    if ( scanf( "%d", &val ) != 1 )
    {
        printf( "Invalid input!\n" );
        return -1;
    }

    printf( "The number incremented is %d\n", val 1 );

    printf( "Enter any number again: " );
    if ( scanf( "%d", &val ) != 1 )
    {
        printf( "Invalid input!\n" );
        return -1;
    }

    printf( "The number decremented is: %d\n", val-1 );

    return 0;
}

This program has the following behavior:

Enter any number: abc
Invalid input!
Enter any number: 5
The number incremented is 6
Enter any number again: abc
Invalid input!
Enter any number: 5
The number incremented is 6
Enter any number again: 10
The number decremented is: 9

However, this solution is not perfect. For example, if the user enters 5abc in the first line, then the first scanf successfully reads 5, but the second scanf will fail:

Enter any number: 5abc
The number incremented is 6
Enter any number again: Invalid input!

If you don't want this counter-intuitive behavior, then it would probably be best not to use the function scanf for line-based user input, but to rather use the functions fgets and strtol instead, for example like this:

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

int get_int_from_user( const char *prompt );

int main( void )
{
    int val;

    val = get_int_from_user( "Enter any number: ");
    printf( "The number incremented is %d\n", val 1 );

    val = get_int_from_user( "Enter any number again: ");
    printf( "The number decremented is: %d\n", val-1 );

    return 0;
}

int get_int_from_user( const char *prompt )
{
    //loop forever until user enters a valid number
    for (;;)
    {
        char buffer[1024], *p;
        long l;

        //prompt user for input
        fputs( prompt, stdout );

        //get one line of input from input stream
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            fprintf( stderr, "Unrecoverable input error!\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;
        l = strtol( buffer, &p, 10 );
        if ( p == buffer )
        {
            printf( "Error converting string to number!\n" );
            continue;
        }

        //make sure that number is representable as an "int"
        if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
        {
            printf( "Number out of range error!\n" );
            continue;
        }

        //make sure that remainder of line contains only whitespace,
        //so that input such as "6sdfj23jlj" 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 l;

    continue_outer_loop:
        continue;
    }
}

This program has the following behavior:

Enter any number: 5abc
Unexpected input encountered!
Enter any number: abc
Error converting string to number!
Enter any number: 5
The number incremented is 6
Enter any number again: 10
The number decremented is: 9

Note that my second program is more sophisticated than the first program, because it keeps on prompting the user for input until the user enters a valid int, whereas the first program simply prints an error message and returns -1.

I took the function get_int_from_user from this answer of mine to another question. See that answer for more information on the extensive input validation that the function performs.

CodePudding user response:

The first scanf is looking for an integer if it doesn't get an integer it does nothing,

The secoind scanf is looking for an integer if it doesn't get an integer it does nothing.

If the first scanf does nothing, nothing changes, so the second identical scanf presented with the same environment will also do nothing.

one way to fix this is to tell the second scanf to discard the garbage characters.

scanf("%*[^0-9]%d",&val);

Subsequent edits to the question made that solution unsuitable.

#include <stdio.h>
int main(){
    int val;
    char junk[2];

    printf("Enter any number: ");
    if( scanf("%d%1[\n]",&val,&(junk[0])) < 2)
    {
         puts("numbers only please");
         return 1;
    }
    printf("The number incremented is %d\n",val 1);
    printf("Enter any number again: ");
    if( scanf("%d%1[\n]",&val,&(junk[0])) < 2)
    {
         puts("numbers only please");
         return 1;
    }
    printf("The number decremented is: %d\n",val-1);
    return 0;
}
  • Related