0

How I can exclude characters from being entered as a value in my programs?

Is there a way through the scanf function to recognize the input as a character and then write a printf to show an invalid value message? It would be more recognizing the character then printing the message I'm concerned with.

Edit: So as asked, the below is my code for a program that first reads five numbers(each between 1 and 30).For each number read, the program should print a line containing that number of adjacent asterisks.

For this, if I enter a number value it causes the program to stop working. So if i could add a way to create "Try again" message or something similar when they are entered, this will stop it from having errors.

#include <stdio.h>

int main(void)
{
  int number1 = 0; int counter;
  int sentinelcount = 1;


  printf("Please enter 5 values, between 1 and 30");

  while (sentinelcount <= 5) {

    
        printf("\n\nEnter number: \n"); /*prompt*/
        scanf_s("%d", &number1); /*read an interger*/
        sentinelcount++;

        if (number1 < 1 || number1 > 30)
        {
            sentinelcount--;
            printf("\nWrong Value\n");
        }

    
    
        if (number1 < 1 || number1 > 30) 
        {
            printf("Enter within correct value range: 1 - 30! ");
        }
        else if (number1 >= 1 || number1 <= 30) 
        {
            printf("Number of asterisks:\n");
                  for (counter = 1; counter <= number1; 
                       counter++) 
                  {
                  printf("*");
                  }
        }

}
return 0;
Dada
  • 6,313
  • 7
  • 24
  • 43
Cik02
  • 59
  • 6
  • 1
    Yes it can be done. Please go through any C book or tutorial, attempt some code and then come back to show your code and describe any specific problem you have with it. A good place to start with be to enter "c scanf" into your fav search engine and read the posts and examples. – kaylum Nov 27 '21 at 19:34
  • 1
    If you want to read in a line of input and the look at the characters in that input, you can write code to do that. If you run into trouble, ask a question about the specific part you had trouble with. – David Schwartz Nov 27 '21 at 19:35
  • 1
    The sad truth is that `scanf` is pretty terrible at error handling. If you want the user to be able to enter an integer, or a floating-point fraction, or a string (without spaces), and if the user types what they're supposed to type, `scanf` is fine. For much of anything beyond that, although you might be able to get it to do approximately what you want (after *lots* of fussing), it's usually just not worth it. If you do you use `scanf`, make sure you check its return value so that you'll at least know whether it read the 1 thing you asked for, or not. – Steve Summit Nov 27 '21 at 20:20
  • There is no way in standard C to prevent users to enter the wrong characters. It is possible when you use some external libraries which are hardware and implementation related. – 0___________ Nov 27 '21 at 20:24
  • When you say `"exclude characters from being entered as a value in my programs"`, what exactly do you mean with `"value"`? You you mean `"number"`? Are you attempting to read a number from the user, and if the user enters input containing characters that can't belong to a number, you want to print an error message instead of accepting the input? Is that what you want? – Andreas Wenzel Nov 27 '21 at 20:29
  • 1
    Ciaran Kiernan, What should happened then with input that is not numeric? Code consumes it and throws away. leave for the next input operation, stop code? You have described you want to detect bad input, but not what to do with it. – chux - Reinstate Monica Nov 27 '21 at 20:37
  • 2
    And using `scanf_s()` because Microsoft lied to you about `scanf()` being "deprecated" and `scanf_s()` being "safer" just makes your code non-portable. (These "safer" calls date to the worst period of [Microsoft's "embrace, extend, extinguish" practices](https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguish)) – Andrew Henle Nov 27 '21 at 20:49

3 Answers3

0

How do I stop characters from being entered into program

Short of some magic hand that prevents the user from typing in non-numeric or a limited key board, the better approach is not to stop characters from being entered, but accept them as input and then detect invalid input.

I recommend to consume invalid input and alert the user of the issue.


A good first attempt is to read a line of input into a string with fgets().

Test for input, conversion success, extra junk and range.

char buf[80];
if (fgets(buf, sizeof buf, stdin)) {  // TBD deal with lines longer than 79

If a line was read, process it with strtol(), sscanf(), etc. Use "%n" to detect where scanning ended. Perform error checking.

  int num;
  int n;
  // If an integer was parsed with no trailing junk and in range ...
  if (sscanf(buf, "%4d %n", &num, &n) == 1 && buf[n] == 0 && 
      (num >= 1 && num <= 30)) {
    Oh_Happy_Day(); // TBD code
  } else {
    Invalid_input(): // TBD code
  }
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

One way to determine whether the user entered a character or a number is to call scanf with the %d conversion format specifier, and check the return value of scanf. If it returns 1, then the conversion format specifier was successfully matched. Otherwise, you print an error message and prompt the user again to enter input. For example:

#include <stdio.h>

int main( void )
{
    int i;

    //infinite loop, equivalent to while(1)
    //repeat the loop until the input is valid
    for (;;)
    {
        //prompt user for input
        printf( "Please enter a number: " );

        //attempt to read and convert user input
        if ( scanf( "%d", &i ) == 1 )
        {
            //input was valid
            break;
        }

        //print error message
        printf( "Input was invalid, please try again!\n" );

        //discard remainder of line
        for ( int c; c = getchar(), c != '\n' && c != EOF; )
            ;
    }

    printf( "Input was successfully converted to the number %d.", i );
}

This is the output of the program:

Please enter a number: sjdfk
Input was invalid, please try again!
Please enter a number: erlh89 
Input was invalid, please try again!
Please enter a number: 34
Input was successfully converted to the number 34.

However, this code has one problem: It will accept input such as "6sdfj23jlj" as valid input for the number 6:

Please enter a number: 6sdfj23jlj
Input was successfully converted to the number 6.

You would probably want to reject the input instead, in this case.

The function scanf will do this, because it is not line-based; it only processes as much input as it can to match the %d conversion format specifier.

One thing you could do to detect such invalid input would be to look at the remainder of the line, and verify that it is empty, apart from the newline character:

#include <stdio.h>
#include <stdbool.h>

int main( void )
{
    bool successfully_matched = false;
    bool found_newline = false;
    int i;

    //infinite loop, equivalent to while(1)
    //repeat the loop until the input is valid
    for (;;)
    {
        //prompt user for input
        printf( "Please enter a number: " );

        //attempt to read and convert user input
        if ( scanf( "%d", &i ) == 1 )
            successfully_matched = true;

        //verify that remainder of line is empty
        if ( getchar() == '\n' )
            found_newline = true;

        //break loop if everything was ok
        if ( successfully_matched && found_newline )
            break;

        //print error message
        printf( "Input was invalid, please try again!\n" );

        //discard remainder of line, if necessary
        if ( !found_newline )
        {
            for ( int c; c = getchar(), c != '\n' && c != EOF; )
                ;
        }
    }

    printf( "Input was successfully converted to the number %d.", i );
}

Now, the program correctly rejects 6sdfj23jlj as invalid input:

Please enter a number: 6sdfj23jlj
Input was invalid, please try again!
Please enter a number: 

However, this code will reject input such as 21 (note the space character after the number). I'm not sure if you want to reject input simply because of a trailing space. If you want to allow spaces and other whitespace characters, then this is possible too, but would require a bit more coding.

In your question, you stated that even if the input is a valid number, you want to additionally check whether the number is in a certain range. This can be accomplished too. However, since the code is starting to get complicated, it seems better to create a new function get_int_from_user to actually get a number from the user. After calling that function, we can then perform the range check, and if the number is not in the desired range, we print an error message and then call the function again.

#include <stdio.h>
#include <stdbool.h>

int get_int_from_user( const char *prompt )
{
    bool successfully_matched = false;
    bool found_newline = false;
    int i;

    //infinite loop, equivalent to while(1)
    //repeat the loop until the input is valid
    for (;;)
    {
        //prompt user for input
        printf( "%s", prompt );

        //attempt to read and convert user input
        if ( scanf( "%d", &i ) == 1 )
            successfully_matched = true;

        //verify that remainder of line is empty
        if ( getchar() == '\n' )
            found_newline = true;

        //break loop if everything was ok
        if ( successfully_matched && found_newline )
            break;

        //print error message
        printf( "Input was invalid, please try again!\n" );

        //discard remainder of line, if necessary
        if ( !found_newline )
        {
            for ( int c; c = getchar(), c != '\n' && c != EOF; )
                ;
        }
    }

    return i;
}

int main( void )
{
    int i;

    //repeat until input is in the desired range
    for (;;)
    {
        //read number from user
        i = get_int_from_user( "Please enter a number: " );

        //perform range check on number
        if ( 1 <= i && i <= 30 )
        {
            //input is in the desired range
            break;
        }

        //print error message
        printf( "Number is not in the desired range, please try again!\n" );
    }

    printf( "The number %d is in the desired range.", i );
}

This program has the following output:

Please enter a number: 342
Number is not in the desired range, please try again!
Please enter a number: 27
The number 27 is in the desired range.

However, I generally do not recommend using scanf for line-based user input. As previously stated, the function scanf does not read one line of input at a time. This means that is can leave leftovers of the line on the input stream, which can be confusing to the programmer, and can lead to bugs, such as this one. See this question for more information on the disadvantages of using scanf.

For line-based user input, it is generally better to use the function fgets. Here is a very robust implementation of the function get_int_from_user which I copied from this previous answer of mine to another question. This function uses fgets and strtol instead of scanf, and performs extensive input validation and error checking:

#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 )
{
    for (;;) //loop forever until user enters a valid number
    {
        char buffer[1024], *p;
        long l;

        fputs( prompt, stdout );

        //get one line of input from input stream
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            fprintf( stderr, "unrecoverable error reading from input\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;
    }
}
Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
0

If you want to exclude characters from being in your code you can use something like this:

unsigned long long answer1,answer2,answer3,c;

scanf("%*[^0123456789]%llu%*[^0123456789]%llu%*[^0123456789]%llu",&answer1,&answer2,&answer3);
printf("%lld %lld %lld",answer1,answer2,answer3);

return 0;

and if you want to print characters you shouldn't scan characters like this: scanf("%d"&a) instead you scan them with this: scanf("%c",&a) and the same point stands in print. but with this you can only scan one character at a time and if you want to scan more than that use more %c in the scanf and printf.

Dada
  • 6,313
  • 7
  • 24
  • 43
Pouriya
  • 1
  • 1