C 无限循环扫描函数

C 无限循环扫描函数,c,scanf,C,Scanf,我正在学习c语言,并且理解这种语言是低级的,在这种情况下缺乏异常处理 我制作了一个简单的程序,用户可以从菜单中选择一些选项。就这么简单 程序分为几个方法-其中一个方法等待用户按键-需要一个整数。然后将这个整数返回给另一个保存开关结构的方法 当按下一个字符时,问题就出现了——在大多数情况下,else块的无限循环被启动 您必须选择一个备选方案0-2。请重试:-) 您必须选择一个备选方案0-2。请重试:-) 您必须选择一个备选方案0-2。请重试:-) 。。。。。。等等 我实际上不知道如何解决这个问题。

我正在学习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;
}
#包括
#包括
无效菜单();
无效运行选择(int选择);
int getSelection();
int pause();
内部主(空){
做{
菜单();
运行选择(getSelection());
}while(暂停());
返回0;
}
int pause(){
INTC;
printf(“\n\n按enter继续!”);
fflush(stdout);
/*刷新输入流*/
而((c=getchar())!='\n'&&c!=EOF);
getchar();
返回1;
}
无效菜单(){
看跌期权(“********M E N U********”);
放置(“1.做某事1”);
放置(“2.做某事2”);
放置(“3.做某事3”);
fflush(stdout);
}
无效运行选择(整数选择){
开关(选择){
案例0:
放置(“您按下了0”);
打破
案例1:
放置(“您按下1”);
打破
案例2:
放置(“您按了2”);
打破
}
}
int getSelection(){
int键;
int真=0;
做{
scanf(“%d”和键)(&key);

如果(key>=0&&key您得到一个无限循环,因为scanf正在从输入缓冲区读取一个字符。缓冲区中还有一个剩余字符,换行符
'\n'

使用以下宏,而不是直接使用scanf

#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);
}
以下主题包含有关此宏以及如何使用它的说明:

为什么没有像其他地方一样删除
getSelection
中的尾部
'\n'

使用:


getSelection
too

编辑:当我第一次写这个答案时,我是如此愚蠢,对
scanf()
的工作原理一无所知

  • 首先让我澄清一点,
    scanf()
    不是一个坏函数,如果我不知道
    scanf()
    如何工作并且我不知道如何使用它,那么我可能没有阅读
    scans()
    的手册,这不可能是
    scanf()
    的错
  • 其次,为了理解代码的错误,您需要了解
    scanf()
    的工作原理
在代码中使用
scanf(“%d”,&key)
时,
scanf(
)尝试从输入中读入整数,但如果输入非数值,
scanf()
知道它不是正确的数据类型,因此它会在下一个循环周期将读取输入放回缓冲区,但无效输入仍在缓冲区中,这将导致
scanf()
再次失败,因为缓冲区尚未清空,而此循环将永远持续下去

为了解决这个问题,可以使用
scanf()的返回值
,这将是成功读取的输入数,但是您需要通过刷新缓冲区来丢弃无效输入,以避免无限循环,当按下
enter
键时,输入缓冲区将被刷新,您可以使用
getchar()执行此操作
函数暂停以获取输入,这将要求您按enter键,从而丢弃无效的输入。请注意,无论您是否输入了正确的数据类型,这不会使您按两次enter键,因为
换行符仍将在缓冲区中。在
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);
do
{
status=scanf(“%d”和键)(&key);
getchar();//通过读取字符并丢弃它来刷新缓冲区
如果(键>=0&&key
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);