【问题标题】:scanf not waiting for input [duplicate]scanf不等待输入[重复]
【发布时间】:2013-12-30 02:24:03
【问题描述】:

虽然这是一个非常简单的问题,但我正在编写一个程序,它陷入了无限的“while”循环,因为中断循环的参数是由需要用户输入的 switch 语句确定的。问题是程序永远不会停止输入,因此它不断选择默认情况,导致无限循环。

这是我目前的代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    float nickels, dimes, quarters, total, price;
    char input;
    price = 1.00;
    total = 0;

    while(total < price){
        printf("n = nickel, d = dime, q = quarter: ");
        scanf("%c", &input);

        switch(input){
        case 'n': case 'N':
            total += 0.05;
            printf("\nTotal: %f\n", total);
            break;
        case 'd': case 'D':
            total += 0.10;
            printf("\nTotal: %f\n", total);
            break;
        case 'q': case 'Q':
            total += 0.25;
            printf("\nTotal: %f\n", total);
            break;
        default:
            printf("\nWrong input\n");
            break;
        }
    }

    printf("You're done! Total is %f", total);

    return 0;
}

我知道这是一个非常简单的问题。我为此道歉。这很可能是我忽略的东西。

【问题讨论】:

  • 不要scanf()只是不要。fgetc()fgets() 供用户输入。
  • "%c" 改为" %c"
  • @DennisMeng 一如既往。我们能否删除scanf() & co。来自 C14?
  • @PhillipKinkade 我知道它不会退出 while 循环,我也不希望它退出。我希望它回到 while 循环的开头并等待用户输入。
  • @Naveed(和 rsheeler):我认为 this 帖子会回答您的问题。

标签: c switch-statement user-input


【解决方案1】:

简而言之,scanf() 在您使用时消耗了用户的输入字符,但没有消耗他也必须输入的换行符,将其留给循环的下一次迭代来跳过。最简单的解决方法是通过添加

来忽略用户输入中的换行符
    case '\n': break;

switch 语句,以便它们被静默使用,而不是触发default 情况。

也就是说,这里是对幕后发生的事情的更详细的解释:

一般来说,I/O 操作比初学者书籍和课程所描述的要复杂得多。 C 运行时库所提倡的自然 I/O 形式的好处是,它将访问数据的大部分细节隐藏在灵活的“流”概念后面。

流通常是缓冲的,这意味着对流的读取和写入实际上是在内存中的缓冲区上进行的,因此实际将数据移入和移出内存的昂贵系统调用可以较少发生并且一次处理更多字节.在处理大文件时,这是一个巨大的好处,并且使得处理整个文件(显然是一次处理一个字符)变得切实可行。

然而,完全缓冲的流对于交互式使用来说确实不方便,因此典型的实现将使stdinstdoutstderr 流在与交互式终端关联时成为“行缓冲”。当输出流被行缓冲时,它会在打印换行符时将缓冲区刷新到终端。当输入流被行缓冲时,它会一次填充输入缓冲区一行。

这尤其意味着第一次调用scanf()(或getchar()stdin上的任何其他读取操作)显然会阻止执行,直到用户键入换行符,然后继续返回预期的内容返回。

在您的情况下,scanf("%c", &amp;input); 将阻塞,直到用户输入换行符,然后将输入的第一个字符复制到 input,将任何其他字符 和换行符留在缓冲区中。下一次循环时,scanf("%c", &amp;input); 将从缓冲区中取出下一个字符,而无需等待任何进一步的输入。我们知道至少有一个这样的字符,因为第一个循环等待输入“d\n”,但随后只消耗“d”,将“\n”留待以后使用。

今天普遍接受的最佳做法是根本不使用scanf()。最好使用fgets(),然后适当地解析整行输入。对于您的示例,您可以读取一行,然后计算所有出现的“n”、“d”和“q”。当然,细节取决于您应该实现的规范。

我提到了“缓冲”和“行缓冲”流。还有第三种更适合交互使用的流。通常可以使流本身“无缓冲”,这样每次调用 stdio 函数都会立即在设备或文件中生效。无缓冲操作只推荐用于交互式程序,所以要使用它,您应该验证stdin 确实连接到终端,而不是从文件重定向。您还需要处理这样一个事实,即终端设备驱动程序本身几乎肯定会尝试至少行缓冲其输入。将有一种特定于系统的方法将终端驱动程序置于原始模式,其中每个字符类型都会立即从 read(2) 系统调用返回,从而允许程序响应单个按键而无需等待回车键按下。实际上配置这种操作模式很棘手,特定于平台,并且远远超出了这个问题的范围。

【讨论】:

  • 我还有一个问题(对不起!)我正在通过创建冒泡排序来处理循环中的整数输入。我最初的问题是循环不会等待输入,所以我使用 c++ cin.ignore() 函数解决了这个问题。但是,array[0] 将始终显示为 22;我没有办法。除非我为第一个位置或 0 索引输入 2 个数字,否则它也不会填充数组的其余部分。这是我迄今为止的代码link我认为它可能与某种输入细微差别有关
  • @rsheeler 我强烈建议您提出一个单独的问题,并在问题中包含相关的代码片段。你会得到更好的回应,而且来自实际使用 C++ 而我个人不使用的人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-22
  • 2015-04-12
  • 1970-01-01
相关资源
最近更新 更多