带有 %d 的字符输入导致无限循环
Character input with %d causing infinite loop
int valid=0, running=1;
printf("\n1. Generate\n2. Retrieve");
while(!valid){
printf("\n\nEnter choice> ");
scanf("%d", &c);
if(c==1){
valid=1;
generate();
while(running){
printf("\n\nPress Y to generate again. Press N to retrieve> ");
scanf(" %c", retry);
if(retry == 'Y' || retry == 'y'){
idx++;
generate();
}else if(retry == 'N' || retry == 'n')
running = 0;
else
printf("Invalid input. Try again.");
}
retrieve();
}else if(choice==2){
valid = 1;
retrieve();
}else
printf("Invalid input. Try again");
}
这里用户应该输入 1 或 2。如果用户输入任何其他数字或字符,那么我想要求用户再次输入。如果用户输入任何其他数字(如 5/6/7 等),程序运行良好。但如果用户输入字符,程序将进入无限循环。我可以通过 scanf 状态检查来打破循环,但程序会停止。相反,如果用户输入除 1 或 2 以外的任何内容,我想提示用户再次输入。
scanf
returns 成功输入分配的次数,或 EOF
文件末尾或错误。您应该养成检查此 return 值的习惯。在 scanf( "%d", &c )
的情况下,您应该期望 return 值 1
成功输入。
%d
转换说明符告诉 scanf
跳过任何前导空格,然后读取第一个 不是 小数的字符数字,将该字符留在输入流中。
示例 - 假设您输入 "12.3"
作为输入。 scanf( "%d", &c )
将读取、转换输入的 "12"
部分并将其分配给 c
和 return 1
。输入的 ".3"
部分留在输入流中。
如果你再次调用scanf( "%d", &c )
,它首先看到的是那个'.'
字符,所以它会立即停止读取(你有一个匹配失败 ).
由于实际上没有读取任何输入,因此没有任何内容分配给 c
和 scanf
returns 0
。这种情况会一直发生,直到您使用 getchar()
或 scanf( "%*c" )
等其他输入操作删除 '.'
字符。
您应该始终检查 scanf
的结果,以确保您阅读了预期的条目数:
int r = 0;
do
{
r = scanf( "%d", &c );
if ( r == EOF )
{
// end of file or error signaled on the input stream; in this case we
// just exit the program
exit( 0 );
}
else if ( r == 0 )
{
// matching failure - there's a bad character in the input stream
// remove it with getchar and try again
getchar();
}
} while( r != 1 );
// at this point we either have good input or have already exited the program
显然,使用 scanf
和 %d
,但输入字符会导致缓冲区问题。请参阅下面的代码,了解避免该问题的一种方法:
#include <stdio.h>
#include <stdlib.h>
void generate(){
printf("generate\n");
}
void retrieve(){
printf("retrieve\n");
}
int main(){
int valid=0, running=1, idx=0, c=-100;
char retry;
char s[25];
printf("\n1. Generate\n2. Retrieve");
while(!valid){
printf("\n\nEnter choice> ");
scanf("%s", s);
c = atoi(s);
if(c==1){
valid=1;
generate();
while(running){
printf("\n\nPress Y to generate again. Press N to retrieve> ");
while(scanf(" %c", &retry)==0);
if(retry == 'Y' || retry == 'y'){
idx++;
generate();
}else if(retry == 'N' || retry == 'n')
running = 0;
else
printf("Invalid input. Try again.");
}
retrieve();
}else if(c==2){
valid = 1;
retrieve();
}else
printf("Invalid input. Try again");
}
return(0);
}
一种可能的执行方式如下所示:
1. Generate
2. Retrieve
Enter choice> Bad
Invalid input. Try again
Enter choice> Worse
Invalid input. Try again
Enter choice> 1
generate
Press Y to generate again. Press N to retrieve> Y
generate
Press Y to generate again. Press N to retrieve> n
retrieve
int valid=0, running=1;
printf("\n1. Generate\n2. Retrieve");
while(!valid){
printf("\n\nEnter choice> ");
scanf("%d", &c);
if(c==1){
valid=1;
generate();
while(running){
printf("\n\nPress Y to generate again. Press N to retrieve> ");
scanf(" %c", retry);
if(retry == 'Y' || retry == 'y'){
idx++;
generate();
}else if(retry == 'N' || retry == 'n')
running = 0;
else
printf("Invalid input. Try again.");
}
retrieve();
}else if(choice==2){
valid = 1;
retrieve();
}else
printf("Invalid input. Try again");
}
这里用户应该输入 1 或 2。如果用户输入任何其他数字或字符,那么我想要求用户再次输入。如果用户输入任何其他数字(如 5/6/7 等),程序运行良好。但如果用户输入字符,程序将进入无限循环。我可以通过 scanf 状态检查来打破循环,但程序会停止。相反,如果用户输入除 1 或 2 以外的任何内容,我想提示用户再次输入。
scanf
returns 成功输入分配的次数,或 EOF
文件末尾或错误。您应该养成检查此 return 值的习惯。在 scanf( "%d", &c )
的情况下,您应该期望 return 值 1
成功输入。
%d
转换说明符告诉 scanf
跳过任何前导空格,然后读取第一个 不是 小数的字符数字,将该字符留在输入流中。
示例 - 假设您输入 "12.3"
作为输入。 scanf( "%d", &c )
将读取、转换输入的 "12"
部分并将其分配给 c
和 return 1
。输入的 ".3"
部分留在输入流中。
如果你再次调用scanf( "%d", &c )
,它首先看到的是那个'.'
字符,所以它会立即停止读取(你有一个匹配失败 ).
由于实际上没有读取任何输入,因此没有任何内容分配给 c
和 scanf
returns 0
。这种情况会一直发生,直到您使用 getchar()
或 scanf( "%*c" )
等其他输入操作删除 '.'
字符。
您应该始终检查 scanf
的结果,以确保您阅读了预期的条目数:
int r = 0;
do
{
r = scanf( "%d", &c );
if ( r == EOF )
{
// end of file or error signaled on the input stream; in this case we
// just exit the program
exit( 0 );
}
else if ( r == 0 )
{
// matching failure - there's a bad character in the input stream
// remove it with getchar and try again
getchar();
}
} while( r != 1 );
// at this point we either have good input or have already exited the program
显然,使用 scanf
和 %d
,但输入字符会导致缓冲区问题。请参阅下面的代码,了解避免该问题的一种方法:
#include <stdio.h>
#include <stdlib.h>
void generate(){
printf("generate\n");
}
void retrieve(){
printf("retrieve\n");
}
int main(){
int valid=0, running=1, idx=0, c=-100;
char retry;
char s[25];
printf("\n1. Generate\n2. Retrieve");
while(!valid){
printf("\n\nEnter choice> ");
scanf("%s", s);
c = atoi(s);
if(c==1){
valid=1;
generate();
while(running){
printf("\n\nPress Y to generate again. Press N to retrieve> ");
while(scanf(" %c", &retry)==0);
if(retry == 'Y' || retry == 'y'){
idx++;
generate();
}else if(retry == 'N' || retry == 'n')
running = 0;
else
printf("Invalid input. Try again.");
}
retrieve();
}else if(c==2){
valid = 1;
retrieve();
}else
printf("Invalid input. Try again");
}
return(0);
}
一种可能的执行方式如下所示:
1. Generate
2. Retrieve
Enter choice> Bad
Invalid input. Try again
Enter choice> Worse
Invalid input. Try again
Enter choice> 1
generate
Press Y to generate again. Press N to retrieve> Y
generate
Press Y to generate again. Press N to retrieve> n
retrieve