检查 C 中的循环 - scan() 不是 运行 秒运行
Checking Loop in C - scan() is not running by the second run
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 前面设置 space 的东西,但它也不起作用...
你有什么好主意吗?
在 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] != '[=11=]'; 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
将读取第一个 word 而不是整行。要获得更强大的解决方案,您应该改用 fgets
。可以在 Andreas Wenzel 提供的答案中看到此类解决方案的示例。
正如我所见,您正在比较 *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 );
问题是,如果您第一次输入类似“sdfokhs”的内容,那么 scanf
将无法匹配任何整数,并且会 return 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
的 return 值总是一个好主意。
但是,在这种情况下,我不建议使用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 = '[=12=]';
//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 != '[=12=]' )
{
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,如果循环也可以使用。但是,在这种情况下,我认为这是最干净的解决方案。
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 前面设置 space 的东西,但它也不起作用... 你有什么好主意吗?
在 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] != '[=11=]'; 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
将读取第一个 word 而不是整行。要获得更强大的解决方案,您应该改用 fgets
。可以在 Andreas Wenzel 提供的答案中看到此类解决方案的示例。
正如我所见,您正在比较 *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 );
问题是,如果您第一次输入类似“sdfokhs”的内容,那么 scanf
将无法匹配任何整数,并且会 return 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
的 return 值总是一个好主意。
但是,在这种情况下,我不建议使用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 = '[=12=]';
//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 != '[=12=]' )
{
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,如果循环也可以使用。但是,在这种情况下,我认为这是最干净的解决方案。