繁体   English   中英

仅C语言中的输入验证整数

[英]Input validation in C only Integer

我的程序是马里奥金字塔。 我似乎无法了解C语言中的输入验证。 如果有人可以解释输入验证以及什么地方出了问题。 谢谢。 这是我的代码的副本。

// Prompt user till input is 0-23
do
{
    printf("Welcome to Mario Pyramid Builder! Enter a number from 0 - 23: ");
    scanf("%d", &height);
    if(height >= 0 && height <= 23)
    {
        break;
    }
    else
    {
        printf("Wrong Input! Try Again.");
        continue;
    }
}
while ((height < 0) || (height > 23));

scanf不会删除多余的字符,它只会提取您放入格式说明符中的内容,其他字符(例如\\ n)保留在缓冲区中。 为避免scanf复杂性,请改用fgets从键盘读取一行,然后使用sscanf()提取整数(或仅使用普通的atoi() )。

...
char buffer[128];
if (fgets( buffer, sizeof(buffer), stdin) != NULL)
{
  if (sscanf(buffer, "%d", &height) == 1) 
  {
    if (height >= 0 && height <= 23)
    {
      ...
    }
    else
    {
      fprintf(stderr, "Height outside valid range [0,23]\n");
    }
  }
  else
  {
    fprintf(stderr, "Please enter a numeric Height in range [0,23]\n");
  }
}
...

用C语言进行输入验证很麻烦 ,需要您自己做一些工作。 不要依赖scanf做艰苦的工作适合你,因为它不会。 如果输入类似12dw的输入,则带有%d转换说明符的scanf将成功读取,转换并将12分配给您的目标,同时将dw留在输入流中,以阻塞下一次读取。

理想的交互式输入,您应该将输入读入文本缓冲区并自己转换为目标类型。 这将有助于防止上述情况的发生,并且在有令人讨厌的长输入试图进行溢出攻击或类似攻击时提供帮助。

因此,从输入缓冲区的固定大小的char数组开始:

#define MAX_INPUT_LENGTH 13     // enough for 32-bit decimal integer, plus sign
char input[MAX_INPUT_LENGTH+1]; // +1 for string terminator

您将使用fgets读取输入:

if ( !fgets( input, sizeof input, stdin ) )
{
  // error on input
}
else
{
  // process input
}

您要进行的下一个检查是查看输入缓冲区中是否有换行符-如果没有,则您的用户输入的值太大,无法表示为本机整数类型。 如果是这样,您将要舍弃当前输入,然后读取并舍弃直到下一个换行符的所有内容:

char *newline = strchr( input, '\n' );
if ( !newline )
{
  while ( getchar() != '\n' ) // read and discard everything up to the next newline
    ;
}
else
{
  // convert input
}

现在,您可以将输入从文本转换为整数。 为此使用strtol库函数(其原型包括stdlib.h ),因为它将允许检查输入中是否有任何非数字,非空格字符。

char *chk;
height = (int) strtol( input, &chk, 0 );
if ( !isspace( *chk ) || *chk != 0 ) // include ctype.h for isspace
{
  // conversion was unsuccessful, bad input
}
else
{
  // check range
}

将所有这些放在一起,您将得到以下内容:

#include <stdlib.h>
#include <ctype.h>
...
#define MAX_INPUT_LENGTH 13
...
int height;
int done = 0;

printf( "Welcome to Mario Pyramid Builder!\n" );
do
{
  char input[MAX_INPUT_LENGTH+1];
  height = -1;                        // initialize height to an invalid value
  printf( "Enter a number from 0 to 23: " );
  if ( !fgets( input, sizeof input, stdin ) )
  {
    fprintf( stderr, "Error on input, try again!\n" );
  }
  else
  {
    //
    // make sure input wasn't too long for the input buffer by 
    // checking for a newline.
    //
    char *newline = strchr( input, '\n' );
    if ( !*newline )
    {
      while ( getchar() != '\n' )
        ;
      fprintf( stderr, "Input too long, try again!\n" );
    }
    else
    {
      //
      // Convert text in input buffer to an integer.  chk will point
      // to the first character in input that is not a decimal digit.
      // If that character is not 0 or whitespace, then we have
      // bad (non-numeric) input.
      //
      char *chk;
      height = strtol( input, &chk, 10 );
      if ( !isspace( *chk ) || *chk != 0 )
      {
        fprintf( stderr, "Non-numeric input detected, try again!\n" );
      }
      else
      {
        // 
        // if height is between 0 and 23, done will be set to true,
        // and we'll exit the loop.
        //
        done = height >= 0 && height <= 23;
      }
    }
  }
} while ( !done );

暂无
暂无

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

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