无限循环扫描功能

时间:2013-10-05 20:09:05

标签: c scanf

我正在学习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;
}

3 个答案:

答案 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);