简体   繁体   English

C编程-允许/确定/检查以整数形式输入的“空格()”

[英]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. 我正在尝试制作一个C程序,该程序可以确定用户是否输入了整数,如果用户未输入整数,则程序会重试提示用户输入整数,依此类推。 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. 当我在条件语句上使用scanf()返回值时,一切正常,但问题是,当用户输入'whitespace / blankspace / space'(在ascii代码为&#32上)并按'enter'时,我的程序将保持运行状态等待用户输入一些字符或整数。

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. 我只希望如果输入为'whitespace / blackspace / space',程序将重复提示用户输入整数或程序停止。

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. 我是C语言的新手,对此感到很好奇。 I know if i use %[^\\n] <-- code format for scanf() string and convert it to integer, the program that i mean will run correctly. 我知道如果我对scanf()字符串使用%[^ \\ n] <-代码格式并将其转换为整数,我的意思是该程序将正确运行。 Is there another way to solve this using %d code format? 还有另一种使用%d代码格式解决此问题的方法吗? or using scanf() ? 或使用scanf()?

Please help me to break my curiosity, Regards :D 请帮助我打破好奇心,谨记:D

scanf will ignore white spaces and keep looking until it finds a non-white space before trying to do a conversion. scanf将忽略空格,并继续查找,直到找到非空格,然后再尝试进行转换。

I would recommend using fgets to get a line of input and then process the with sscanf. 我建议使用fgets获取输入行,然后使用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. 格式说明符'%* s'在遇到空格(制表符,空格,换行符)时将停止输入字符,因此,如果用户输入了这些字符中的任何一个,这些字符将不会被使用。

the '%d' will consume all such leading white space. '%d'将消耗所有此类前导空白。

when the user enters some 'valid' number, then the code will drop through to the 'else' statement 当用户输入一些“有效”数字时,该代码将进入“ else”语句

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. 当用户输入诸如“ a”之类的ascii值时,“%d”将完成输入,并且代码将进入“ else”语句。 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. 到那时,“ number”变量将不会被设置,因此“ number”将包含“ number”变量所在堆栈中碰巧的每个垃圾。 That 'may' happen to be a integer greater than 0. 该“可能”恰好是大于0的整数。

The value returned from the call to 'scanf()' can be something other than 0 or 1, like EOF 从调用'scanf()'返回的值可以是0或1以外的值,例如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. %s将跳过任何前导空格,然后读取非-空格字符,直到再次看到空格。 So, that scanf( "*%s" ); 因此,该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. 尽管可以说,更好的方法是将所有输入读取为文本,然后使用strtol将文本转换为目标类型,但这种方法在快速而肮脏的测试中“有效”。 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 : 为了测试fgets失败,我输入Ctrl - d发送EOF

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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