简体   繁体   English

如何验证 scanf 数字输入

[英]How can I validate scanf numeric input

I have a simple question.我有一个简单的问题。 I'm learning linked lists and my data type is int .我正在学习链表,我的数据类型是int I'm wondering how can validate it where it doesn't allow to take in alphabetic input.我想知道如何在不允许接受字母输入的地方验证它。

When I do it the way I have it, it doesn't print the message.当我按照我的方式进行操作时,它不会打印消息。 So how can I properly do something like that?那么我怎样才能正确地做这样的事情呢?

My code:我的代码:

node * createLinkedList()
{
    node * head = NULL;
    node * temp = NULL;
    node * p = NULL;
    
    while ((scanf("%d", &(temp->data))) !=EOF )
    {
        if ((temp->data>= 'a' && temp->data<= 'z') || (temp->data>= 'A' && temp->data<= 'Z')){
            fprintf(stderr,"ERROR alph is not allowed");
        }

    }
}

The %d scanf specifier is to read int , if an alphabetic character is inputed, scanf will fail to read it and temp->data will retain its previous value. %d scanf说明符用于读取int ,如果输入字母字符, scanf将无法读取它并且temp->data将保留其先前的值。

A better condition for your cycle would be:您的周期的更好条件是:

while (scanf("%d", &(temp->data)) == 0) //while input is not correctly parsed...
{
    fprintf(stderr, "ERROR alph is not allowed\n"); //...print error message...
    int c;
    while((c = getchar()) != '\n' && c != EOF) {} //...and clear stdin
}

This makes it so that if the input is not parseable as an int a new input will be asked until a good value is inputed.这样一来,如果输入无法解析为int ,则会询问新输入,直到输入合适的值。

Note that, as @JohnBode pointed out , an input starting with a digit but that contains alphabetic characters will be parsed until the character is found, ie 123abc4 will parse 123 .请注意,正如@JohnBode 指出的那样,以数字开头但包含字母字符的输入将被解析,直到找到该字符,123abc4将解析123 If you want to avoid this, using a combination of fgets and strtoll is a more robust method and will allow you to validate inputs like the above.如果您想避免这种情况,结合使用fgetsstrtoll是一种更可靠的方法,并且可以让您像上面那样验证输入。

If it's something that you want to allow to happen, and continue using scanf , don't forget you need to then clear stdin which will have the characters that were not parsed, (in the exemplified case abc4\n ), before asking for new inputs, @JohnBode's answer covers these matters perfectly, check that out.如果这是您希望允许发生的事情,并继续使用scanf ,请不要忘记您需要清除stdin ,其中将包含未解析的字符(在示例情况下abc4\n ),然后再请求新的输入, @JohnBode 的回答完美地涵盖了这些问题,检查一下。


There is another problem in the code you show, your temp pointer is NULL , it is not able to store any data.您显示的代码中还有另一个问题,您的temp指针是NULL ,它无法存储任何数据。 Either declare it as an object or allocate memory for it.将其声明为 object 或为其分配 memory。 As it is, it leads to undefined behavior .实际上,它会导致未定义的行为


If you need to validate integer input, then you can't rely on %d alone.如果您需要验证 integer 输入,则不能仅依赖%d It won't catch and reject bad entries like "12w45" - it will successfully convert and assign "12" but will leave "w45" in the input stream to foul up the next read.它不会捕获并拒绝诸如"12w45"之类的错误条目——它会成功转换并分配"12" ,但会在输入 stream 中留下"w45"以扰乱下一次读取。

There are two ways around this.有两种解决方法。 One is to scan and check the character immediately following the input, like so:一种是在输入后立即扫描并检查字符,如下所示:

int tmp;
char dummy = 0;

int r;

if ( (r = scanf( "%d%c", &tmp, &dummy )) == 2 )
{
  // if following character is whitespace, then this is a valid numeric input
  if ( isspace( dummy ) )
    temp->data = tmp;
  else
  {
    fprintf( stderr, "non-numeric character '%c' (%d) detected in input\n",
      isprint( dummy ) ? dummy : '.', dummy );

    fprintf( stderr, "clearing out input stream\n" );
    while ( getchar() != '\n' )
      ; // empty loop
  }
}
else if ( r == 1 ) // only thing following numeric input was EOF
{
  temp->data = tmp;
}
else if ( r == 0 )
{
  fprintf( stderr, "Non-numeric input detected, clearing input stream\n" );
  while ( getchar() != '\n' )
    ; // empty loop
}
else
{
  fprintf( stderr, "EOF or error detected on input\n" );
}

A better way to do this in my opinion is to avoid using scanf entirely - read your input as a string using fgets , then use strtol or strtod to perform the conversion:在我看来,更好的方法是避免完全使用scanf - 使用fgets将输入作为字符串读取,然后使用strtolstrtod执行转换:

char buffer[13]; // 11 decimal digits plus sign plus string terminator;
                 // should be able to store the decimal string representation
                 // of any 32-bit integer;

if ( fgets( buffer, sizeof buffer, stdin ) )
{
  // chk will point to the first character *not* converted by strtol
  char *chk;
  int tmp = (int) strtol( buffer, &chk, 10 );
  if ( !isspace( *chk ) && *chk != 0 )
  {
    fprintf( stderr, "Detected non-numeric character '%c' (%d) in input\n",
      isprint( *chk ) ? *chk : '.', *chk );
  }
  else
  {
    temp->data = tmp;
  }
}
else
{
  fprintf( stderr, "EOF or error on input\n" );
}

When you're doing this kind of validation, use a temporary to store the converted value until you've finished;当您进行这种验证时,请使用临时存储转换后的值,直到您完成为止; do not update your actual target until you know the value is good.在您知道该值是好的之前不要更新您的实际目标。

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

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