简体   繁体   中英

C Programming - Allow / determine / check “space (&#32)” input in integer

First, sorry for my bad english, okay go to this question above. I was surfing a lot for reference about this question on many websites, but i didn't find the right answer yet.

I'm trying to make a C program which this program can determine if the user input an integer or not, if user didn't input an integer then the program retry prompt to user for input an integer and so on. Everything is ok when i use scanf() return value on conditional statement, but the problem is, when user input 'whitespace/blankspace/space' (on ascii code as &#32) and press 'enter', my program just stay running to wait for user input some characters or integer.

I just wish that if the input is 'whitespace/blackspace/space', the program will repeat prompt to user to input an integer or the program just stop.

Here is the case code :

#include <stdio.h>

int main() {

    int number, isInt;

    printf("Input a number : ");

    do {
        if ((isInt = scanf("%d", &number)) == 0) {
            printf("retry : ");
            scanf("%*s");
        } else if (number < 0) {
            printf("retry : ");
        }
    } while (isInt == 0 || number < 0); 

    printf("%d\n", number);

    return 0;
}

I am a newbie in C, and curious about this. I know if i use %[^\\n] <-- code format for scanf() string and convert it to integer, the program that i mean will run correctly. Is there another way to solve this using %d code format? or using scanf() ?

Please help me to break my curiosity, Regards :D

scanf will ignore white spaces and keep looking until it finds a non-white space before trying to do a conversion.

I would recommend using fgets to get a line of input and then process the with sscanf. Something like this:

#include <stdio.h>
#include <stdlib.h>

int main() {    
    int number=-1;    
    printf("Input a number : ");
    do {
        char line[80];
        if(!fgets(line,sizeof(line),stdin)){
            printf("line read error\n");
            exit(1);
        }
        if (sscanf(line,"%d", &number) !=1) {
            printf("retry : ");
        } else if (number < 0) {
            printf("retry : ");
        }
    } while ( number < 0); 
    printf("%d\n", number);
    return 0;
}

the format specifier '%*s' will stop inputting characters when it encounters a white space (tab, space, newline) so if the user inputs any of those characters they will not be consumed.

the '%d' will consume all such leading white space.

when the user enters some 'valid' number, then the code will drop through to the 'else' statement

when the user enters some ascii value, like 'a' then the '%d' will finish inputting and the code will drop through to the 'else' statement. At that time, the 'number' variable will not have been set So 'number' will contain what every trash that happened to be on the stack where the 'number variable is located. That 'may' happen to be a integer greater than 0.

The value returned from the call to 'scanf()' can be something other than 0 or 1, like EOF

the 'backspace' will be consumed by the terminal driver, so never reach the program.

so your program does exactly what is to be expected, but probably not what you want.

%s will skip over any leading whitespace, then read non -whitespace characters until it sees whitespace again. So, that scanf( "*%s" ); call will block until it sees at least one non-whitespace character.

The %[ conversion specifier will not skip over any leading whitespace, so that may be an acceptable substitute:

scanf( "%*[^\n]" );

This "works" in a quick and dirty test, although to be honest the better approach is to read all input as text, then use strtol to convert the text to the target type. Here's a working example of what I mean:

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

#define BUF_SIZE 20

int main( void )
{
  int value = -1;
  char buf[BUF_SIZE];

  do
  {
    printf( "Gimme a non-negative value: " );
    if ( fgets( buf, sizeof buf, stdin ) )
    {
      char *newline = strchr( buf, '\n' );
      if ( !newline )
      {
        printf( "Input too long for buffer, flushing..." );
        while ( fgets( buf, sizeof buf, stdin ) && !strchr( buf, '\n' ) )
          ;
        printf( "try again\n" );
      }
      else
      {
        *newline = 0; // Remove the newline character from the buffer

        char *chk;    // chk will point to the first character *not* converted
                      // by strtol.  If that character is anything other
                      // than 0 or whitespace, then the input string was
                      // not a valid integer.

        int tmp = (int) strtol( buf, &chk, 0 );
        if ( *chk != 0 && !isspace( *chk ) )
        {
          printf( "%s is not a valid integer, try again\n", buf );
        }
        else if ( tmp < 0 )
        {
          printf( "%d is negative, try again\n", tmp );
        }
        else
        {
          value = tmp;
        }
      }
    }
    else
    {
      printf( "Input failure, bailing out completely\n" );
      break;
    }
  } while ( value < 0 );

  printf( "value is %d\n", value );
  return 0;
}

And, here is an example from a run, exercising each test case:

$ ./format2
Gimme a non-negative value: Supercalifragilisticexpealidocious
Input too long for buffer, flushing...try again
Gimme a non-negative value: 123fgh
123fgh is not a valid integer, try again
Gimme a non-negative value: -12345
-12345 is negative, try again
Gimme a non-negative value: 1234
value is 1234

And to test the fgets failure, I type Ctrl - d to send EOF :

$ ./format2
Gimme a non-negative value: Input failure, bailing out completely
value is -1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM