c - scanf 不等待输入

标签 c switch-statement user-input

这个问题在这里已经有了答案:





C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf [duplicate]

(7 个回答)


7年前关闭。




尽管这是一个非常简单的问题,但我正在编写一个程序,该程序陷入了无限的“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()当您使用它时,它消耗了用户的输入字符,但没有消耗他也必须输入的换行符,将其留给循环的下一次迭代以绊倒。最简单的解决方法是忽略用户输入中的换行符,方法是添加

    case '\n': break;

switch语句,以便它们被静默消耗而不是触发 default案件。

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

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

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

但是,完全缓冲的流对于交互式使用确实不方便,因此典型的实现将使 stdin , stdout , 和 stderr当流与交互式终端相关联时,流将被“行缓冲”。当输出流被行缓冲时,它会在打印换行符时将缓冲区刷新到终端。当输入流被行缓冲时,它一次将输入缓冲区填充一行。

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

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

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

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

关于c - scanf 不等待输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20530556/

相关文章:

c - 在 C 中使用 GTK+ 单击按钮后 GUI 变得无响应

c++ - 如何编译 Duff 的设备代码?

c# - 避免在 switch 语句中进行硬编码

Android,OptionMenu ResourceNotFoundException;当切换到陆地空间

ios - 如何在用户输入字符时测试对 UITextField 的字符输入并防止无效字符

C - char* 列表 - 内存分配

c - 为什么使用 %ebx 寄存器会导致我的汇编代码出现段错误

java - input.nextLine() 在 while 循环内带有一个字符串

c - glibc 的 system() 调用安全吗?

javascript - 如何显示多个用户输入的答案以及如何将其全部写入文本文件