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