C-scan()中的Checking Loop在第二次运行时未运行


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

我正在尝试进行一个检查循环,控制输入的值是否在114之间。如果有字母也必须重复,输入过程。

也许它不起作用,每次在第二次运行时,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。然而,在这种情况下,我相信这是最干净的解决方案。

正如我所看到的,您正在比较*op(我认为它是一个指针(。因此,请检查是否已经为预定义的变量分配了值。它看起来应该是这样的。
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 );

最新更新