问题描述
void openMenu(int *op) {//edited
do {
printf("Your turn...\t\n");
scanf(" %d",op);
if (*op > 14 || *op < 1 ) {
printf("Only enter a number between 1 and 14!\n");
}
} while (*op > 14 || *op < 1 );
}
我正在尝试创建一个检查循环来控制输入的值是否在 1
和 14
之间。如果有字母它也必须重复,输入过程。
也许它不起作用,每次它在第二次运行时都没有运行 scanf。
我检查了在 %d 前面设置一个空格的东西,但它也不起作用...... 你有什么好主意吗?
在 Mac 11.1 上使用 Xcode
解决方法
您需要检查 scanf 的返回值:
#include <stdio.h>
void openMenu(int *op) {//edited
do {
printf("Your turn...\t\n");
if (scanf(" %d",op) != 1 || *op > 14 || *op < 1 ) {
while(getchar()!='\n'); // clean the input buffer
printf("Only enter a number between 1 and 14!\n");
}
} while (*op > 14 || *op < 1 );
}
int main()
{
int op;
openMenu(&op);
printf("Number Read {%d}\n",op);
return 0;
}
更强大(也更复杂)的解决方案如下:
int isNumber(char buffer[]){
for(int i = 0; buffer[i] != '\0'; i++)
if(!isdigit((unsigned char) buffer[i]))
return 0;
return 1;
}
int readInput(char buffer[]){
int result = scanf("%99s",buffer);
while(getchar()!='\n');
return result;
}
int isInRange(int *op,char buffer[]){
*op = atoi(buffer);
return *op <= 14 && *op >= 1;
}
void openMenu(int *op) {
do {
char buffer[100];
if(readInput(buffer) && isNumber(buffer) && isInRange(op,buffer)) {
break;
}
printf("Only enter a number between 1 and 14!\n");
} while (1);
}
这将避免诸如 4odgjlda
之类的输入被视为有效数字。尽管如此,对于当前的方法,诸如 4 odgjlda
之类的输入仍会被视为有效输入,因为 scanf
会读取第一个 单词 而不是整行。要获得更强大的解决方案,您应该改用 fgets
。您可以在 Andreas Wenzel 提供的答案中看到此类解决方案的示例。
问题是,如果你第一次输入类似 "sdfokhs" 的东西,那么 scanf
将无法匹配任何整数并返回 0。因为 scanf
没有消耗这个无效的输入从输入流中,第二次调用 scanf
不会导致用户被提示输入新的输入。相反,scanf
将再次尝试匹配来自非消耗输入的整数,并且会再次失败,原因与第一次相同。这意味着你有一个无限循环。
因此,要解决此问题,您必须在再次调用 scanf
之前使用该行的其余部分,例如:
while ( fgetc( stdin ) != '\n' ) ;
或者,如果您想要更强大的错误检查:
int c;
do
{
c = fgetc( stdin );
if ( c == EOF )
{
printf( "Unrecoverable error reading input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
另外,检查 scanf
的返回值总是一个好主意。
但是,在这种情况下,我不建议使用 scanf
。使用 fgets
在每次循环迭代中始终只读取一行输入会更有意义。使用 scanf
的缺点是每次迭代可能会读取多行输入,或者只读取一行的一部分,这需要您使用该行的其余部分。
以下解决方案比所有其他答案的解决方案都要长,但它也是最稳健的输入验证和错误处理方案。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINESIZE 100
void openMenu(int *op)
{
char buffer[MAX_LINESIZE];
char *p;
long converted;
//goto label
try_again:
//prompt user for input
printf( "Please enter number between 1 and 14: " );
//read line of input into buffer
if ( fgets( buffer,MAX_LINESIZE,stdin ) == NULL )
{
printf( "Unrecoverable error reading input!\n" );
exit( EXIT_FAILURE );
}
//make sure that a full line was read and remember position of newline character
p = strchr( buffer,'\n' );
if ( p == NULL )
{
int c;
printf( "Input was too long!\n" );
//attempt to consume input until newline character found
do
{
c = fgetc( stdin );
if ( c == EOF )
{
printf( "Unrecoverable error reading input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
goto try_again;
}
//remove newline character from string
*p = '\0';
//convert string to number
converted = strtol( buffer,&p,10 );
//make sure conversion was successful
if ( p == buffer )
{
printf( "Only enter a number!\n" );
goto try_again;
}
//verify that remainder of line is whitespace
while ( *p != '\0' )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Only enter a number!\n" );
goto try_again;
}
p++;
}
//verify that number was in the correct range
if ( converted < 1 || converted > 14 )
{
printf( "Only enter a number between 1 and 14!\n" );
goto try_again;
}
//since all tests were passed,write the value
*op = converted;
}
注意使用 goto
should normally not be done,如果循环也可以使用。但是,在这种情况下,我认为这是最干净的解决方案。
正如我所看到的,您正在比较 *op(我认为它是一个指针)。 因此,请检查您是否已将该值分配给预定义的变量。 它应该看起来像这样。
int value = 0;
int *op = &value;
do {
printf("Your turn...\t\n");
scanf(" %d",op);
if (*op > 14 || *op < 1 ) {
printf("Only enter a number between 1 and 14!\n");
}
}while (*op > 14 || *op < 1 );