-2

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.

t14njin
  • 33
  • 5
  • `scanf` is too weak to handle errors. Read the input string with `fgets()` from stdin and parse the input string with `strtoul()` (or similar) to get more control. – harper Dec 29 '22 at 11:41
  • 2
    *is there a fix to this?* Don't use `scanf()`. Use `fgets()`/`getline()` and parse the input. – Andrew Henle Dec 29 '22 at 11:42
  • 1
    How `scanf()` behaves when you enter some non integer input after prompt - `Enter any number: `? Have you tried to check the `scanf()` return value when you give input other than a number? I suggest you - read `scanf()` documentation. – H.S. Dec 29 '22 at 11:45
  • It's not a case of don't use scanf() scanf is usefull if you know how to use it, – Jasen Dec 29 '22 at 12:09
  • Suppose you type some non-integer input. What do you want your program to do? – n. m. could be an AI Dec 29 '22 at 12:57
  • 1
    @Jasen *It's not a case of don't use scanf() scanf is usefull if you know how to use it* Yes, it most certainly is a case of "Don't use `scanf()`". Because there's no way to "use" `scanf()` and recover the input stream when unexpected input is read. If you don't know what the input actually is you can't know how to use `scanf()`. – Andrew Henle Dec 29 '22 at 13:11
  • 1
    Related questions: (1). [How to scanf only integer?](https://stackoverflow.com/q/26583717/12149471) (2). [Validate the type of input in a do-while loop C](https://stackoverflow.com/q/31633005/12149471) – Andreas Wenzel Dec 29 '22 at 13:16

2 Answers2

2

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.

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

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;
}
Jasen
  • 11,837
  • 2
  • 30
  • 48
  • 1
    While what you're saying is technically correct, this is a very poor solution – klutt Dec 29 '22 at 12:57
  • 2
    This doesn't make any sense. If the first scanf failed, why allow the program to proceed to the second scanf? – n. m. could be an AI Dec 29 '22 at 12:58
  • How do you know any values are "garbage"? That can only work in trivial cases. – Andrew Henle Dec 29 '22 at 13:14
  • give an example where it doesn't work. – Jasen Dec 29 '22 at 13:27
  • It won't work if the number starts with a minus sign, for example. Also, if the user enters `abc6` on the first line, then the first input will fail and it will take `6` as the second input, despite that input having been taken from the first line. – Andreas Wenzel Dec 29 '22 at 13:29
  • @n.m that wasn't the question. it also wasn't asked why the first scanf completed with no data. – Jasen Dec 29 '22 at 13:29
  • 1
    *"that wasn't the question"* - OP is clearly a beginner who doesn't know what he is doing. Is your priority to help or to strictly answer the question even if the answer falls under malicious compliance? – klutt Dec 29 '22 at 13:32
  • @klutt I did not make this question to cause malicious compliance, im just a beginner in c. I apologise if this question irritated you. – t14njin Dec 29 '22 at 14:07
  • @t14njin The question did not irritate me at all. What irritated me was Jasens answer, because he present it as if it was a good solution when in reality it is a very bad solution. And since you are a beginner you don't have the knowledge needed to understand that, so Jasen is basically fooling you into bad habits. – klutt Dec 29 '22 at 14:10
  • @t14njin You would be much better of following the advices in the comments about using `fgets` instead – klutt Dec 29 '22 at 14:22
  • Note that meanwhile, OP has clarified the question by specifying the desired behavior, thereby invalidating your answer. Normally, questions should not be modified in such a way that they invalidate existing answers. However, in this case, it was appropriate to modify the question, because it was unclear. Therefore, you may want to adapt your answer to the modified question. – Andreas Wenzel Dec 29 '22 at 15:22
  • have posted a different solution using scanf. – Jasen Dec 29 '22 at 22:59
  • 1
    This solution is inconsistent in that it accepts input with leading whitespace characters, but rejects input with trailing whitespace characters. However, since this is only a minor issue, for which I do not see an easy fix (the solution in my answer for this is rather complicated), I am still upvoting it. – Andreas Wenzel Dec 30 '22 at 08:32