我正在学习c并且理解这种语言是低级的,在这种情况下缺乏异常处理。
我制作了一个简单的程序,用户可以从菜单中选择一些替代方案。就这么简单!
程序分为几种方法 - 其中一种方法等待用户按键 - 预期整数。然后将此整数返回到另一个包含开关结构的方法。
当按下一个字符时会出现问题 - 在大多数情况下,会启动else块的无限循环。
您必须选择其他0 - 2.请再试一次: - )
您必须选择其他0 - 2.请再试一次: - )
您必须选择其他0 - 2.请再试一次: - )
......等等
我实际上并不知道如何解决这个问题。我试图使用scanf函数的返回值,但没有成功。我也尝试将一个字符(而不是整数)作为参数传递给scanf函数 - 也没有成功。
有任何建议如何处理这个问题?
#include <stdio.h>
#include <stdlib.h>
void menu();
void runSelection(int selection);
int getSelection();
int pause();
int main(void) {
do{
menu();
runSelection(getSelection());
}while(pause());
return 0;
}
int pause() {
int c;
printf("\n\nPress enter to continue!");
fflush(stdout);
/* flush inputstream */
while((c = getchar()) != '\n' && c != EOF);
getchar();
return 1;
}
void menu() {
puts(" * * * * * * M E N U * * * * * * *");
puts("1. Do something 1");
puts("2. Do something 2");
puts("3. Do something 3");
fflush(stdout);
}
void runSelection(int selection) {
switch (selection) {
case 0:
puts("you pressed 0");
break;
case 1:
puts("you pressed 1");
break;
case 2:
puts("you pressed 2");
break;
}
}
int getSelection() {
int key;
int true = 0;
do {
scanf("%d", &key);
if (key >= 0 && key <=2) {
true = 1;
}
else {
puts("You must choose an alternative 0 - 2. Please try again :-)");
fflush(stdout);
}
} while (true == 0);
return key;
}
答案 0 :(得分:2)
你有一个无限循环,因为scanf从输入缓冲区读取一个charachter。缓冲区中还有一个新行'\n'
使用以下宏而不是使用scanf directelly
#define SCAN_ONEENTRY_WITHCHECK(FORM,X,COND) \
do {\
char tmp;\
while(((scanf(" "FORM"%c",X,&tmp)!=2 || !isspace(tmp)) && !scanf("%*[^\n]"))\
|| !(COND)) {\
printf("Invalid input, please enter again: ");\
}\
} while(0)
int main()
{
int decision;
printf("Input data, valid choice 1 or 0: ");
SCAN_ONEENTRY_WITHCHECK("%d",&decision,(decision==0 || decision==1));
printf("You have entered good input : %d\n", decision);
}
以下主题包含有关此宏以及如何使用它的说明: Common macro to read input data and check its validity
答案 1 :(得分:0)
为什么你没有像其他地方一样删除'\n'
中的尾随getSelection
?
使用:
int c;
scanf("%d", &key);
while((c = getchar()) != '\n' && c != EOF); //Add this line
在getSelection
答案 2 :(得分:0)
编辑:当我第一次写这个答案的时候,我对scanf()
的工作方式非常愚蠢和无知。
scanf()
不是一个破碎的功能,如果我不知道scanf()
是如何工作的,我不知道如何使用它,那么我可能是避风港请阅读scans()
的手册,但这不是scanf()
的错误。scanf()
的工作原理。在代码中使用scanf("%d", &key)
时,scanf(
会尝试从输入中读取整数,但如果输入非数字值,则scanf()
知道它不是' t正确的数据类型,因此它将读取输入放回缓冲区,在下一个循环周期中,但是无效输入仍然在缓冲区中,这将导致scanf()
再次失败,因为缓冲区尚未清空,这个循环将永远持续下去。
为了解决这个问题,您可以使用scanf()
的返回值,这将是读取的成功输入的数量,但是您需要通过刷新缓冲区来丢弃无效输入以避免无限循环,当按下enter
键时刷新输入缓冲区,你可以使用getchar()
功能暂停获取输入,这需要你按回车键这样丢弃输入无效,请注意,无论您输入的数据类型是否正确,都不会按enter
键两次,因为newline character
仍然在缓冲区中。在scanf()
成功读完输入后的整数后,它会将\n
放回缓冲区,因此getchar()会读取它,但由于你不需要它,所以丢弃它是安全的:
do
{
status = scanf("%d", &key);
getchar(); // flush the buffer by reading a character and discarding it
if (key >= 0 && key <=2)
{
true = 1;
}
else
{
puts("You must choose an alternative 0 - 2. Please try again :-)");
fflush(stdout);
}
} while (true == 0 && status != 1);