仅在C中输入验证整数

时间:2018-03-31 20:28:27

标签: c cs50

我的节目是马里奥金字塔。我似乎无法在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));

2 个答案:

答案 0 :(得分:1)

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");
  }
}
...

答案 1 :(得分:0)

C中的输入验证是屁股中的痛苦,需要您做一些工作。 依靠scanf为您做出艰苦的工作,因为它不会成功。如果您输入12dw之类的输入,scanf %d转换说明符将成功读取,转换并将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 );