简体   繁体   English

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

[英]Input validation in C only Integer

My program is the Mario pyramids. 我的程序是马里奥金字塔。 I can't seem to get the Input Validation in C down. 我似乎无法了解C语言中的输入验证。 If someone could explain input validation and what seems to be going wrong. 如果有人可以解释输入验证以及什么地方出了问题。 Thanks. 谢谢。 Here is a copy of my code. 这是我的代码的副本。

// 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 does not remove extra characters it only extracts what you put in the format specifier, the other characters like \\n remain in the buffer. scanf不会删除多余的字符,它只会提取您放入格式说明符中的内容,其他字符(例如\\ n)保留在缓冲区中。 To avoid scanf complications use fgets instead to read a line from keyboard, then use sscanf() to extract the integer (or just plain old atoi() ) 为避免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");
  }
}
...

Input validation in C is a pain in the ass , and requires a bit of work on your part. 用C语言进行输入验证很麻烦 ,需要您自己做一些工作。 Do not rely on scanf to do the hard work for you, because it won't. 不要依赖scanf做艰苦的工作适合你,因为它不会。 If you enter an input like 12dw , scanf with the %d conversion specifier will successfully read, convert, and assign 12 to your target while leaving dw in the input stream to foul up the next read. 如果输入类似12dw的输入,则带有%d转换说明符的scanf将成功读取,转换并将12分配给您的目标,同时将dw留在输入流中,以阻塞下一次读取。

Ideally for interactive input, you should read your input into a text buffer and convert to the target type yourself. 理想的交互式输入,您应该将输入读入文本缓冲区并自己转换为目标类型。 It will help protect against cases like the above, and it will help in case there's an obnoxiously long input that's attempting an overflow exploit or something like that. 这将有助于防止上述情况的发生,并且在有令人讨厌的长输入试图进行溢出攻击或类似攻击时提供帮助。

So, start with a fixed-size array of char for your input buffer: 因此,从输入缓冲区的固定大小的char数组开始:

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

You'll use fgets to read the input: 您将使用fgets读取输入:

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

The next check you'll want to make is to see if there's a newline in the input buffer - if not, then your user entered a value that's too large to represent as a native integer type. 您要进行的下一个检查是查看输入缓冲区中是否有换行符-如果没有,则您的用户输入的值太大,无法表示为本机整数类型。 If that's the case, you'll want to discard the current input, then read and discard everything up to and including the next newline: 如果是这样,您将要舍弃当前输入,然后读取并舍弃直到下一个换行符的所有内容:

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

Now you're ready to convert your input from text to integer. 现在,您可以将输入从文本转换为整数。 Use the strtol library function for this (include stdlib.h for its prototype), as it will allow to check if there are any non-numeric, non-whitespace characters in the 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
}

Putting all of that together, you get something like this: 将所有这些放在一起,您将得到以下内容:

#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