void openMenu(int *op) {//edited
do {
printf("Your turn...tn");
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...tn");
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] != ' '; 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 = ' ';
//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 != ' ' )
{
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
。然而,在这种情况下,我相信这是最干净的解决方案。
int value = 0;
int *op = &value;
do {
printf("Your turn...tn");
scanf(" %d", op);
if (*op > 14 || *op < 1 ) {
printf("Only enter a number between 1 and 14!n");
}
}while (*op > 14 || *op < 1 );