0

I want to make sure that the character the user enters only works for a natural number. I can do it for letters and symbols because it's a simple "else". But if the user enters a number that contains a decimal point, I want the program to stop with an error code. I know that it simply cuts off the decimal point if I read double into %d.

kristof
  • 19
  • 4
  • 2
    You should post your code. It's kind of hard to infer what you are trying to do. Input + `%d` seems like yet another `scanf` question. Do yourself a favor and [don't use scanf](https://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html). Read the bytes and loop through them looking for a decimal point. Or just use `strtod`, `strtol`, etc... – Jason Dec 01 '22 at 14:53

1 Answers1

0

I generally do not recommend that you use scanf for user input, as that is not what the function was designed to do.

Your question is nearly identical to this question. The only difference is that the linked question asks about how to validate the user input as an integer, whereas you are asking about how to validate the user input as a natural integer, i.e. a positive or non-negative integer (depending on how you define natural number). Therefore, all you must do is use one of the answers from that question and add an additional check whether the number is positive or non-negative.

In the code below, I have modified the function get_int_from_user from my answer to the question mentioned above, by adding this additional check, and have changed the name of the function to get_natural_int_from_user.

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

int get_natural_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 number is non-negative
        if ( l < 0 )
        {
            printf( "Natural numbers must be non-negative!\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;
    }
}

int main( void )
{
    int number;

    number = get_natural_int_from_user( "Please enter a natural number: " );

    printf( "Input was valid.\n" );
    printf( "The number is: %d\n", number );

    return 0;
}

This program has the following behavior:

Please enter a natural number: abc
Error converting string to number!
Please enter a natural number: 6abc
Unexpected input encountered!
Please enter a natural number: 5.7
Unexpected input encountered!
Please enter a natural number: -8
Natural numbers must be non-negative!
Please enter a natural number: 25
Input was valid.
The number is: 25

Note that in your question, you are asking for the program to abort if the input is invalid. However, this program will instead keep reprompting the user for input until it is valid. This behavior is generally more user-friendly.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39