getchar 和 scanf 缓冲区问题。 getchar 没有存储正确的值

getchar and scanf buffer issues. getchar not storing the correct value

我是编程新手,我知道 scanf() 有一些怪癖。也就是说,当它检测到与其转换说明符不匹配的字符时,它会立即 returns 并将有问题的字符放回缓冲区中,以便由另一个 scanf() 调用或其他一些函数读取可以访问缓冲区。 但是,我正在做书本练习,代码行为很奇怪。

    float total = 0, operand = 0;
    char operator = 0;

    printf("Enter an expression: ");

    scanf("%f ", &total);

    while ((operator = getchar()) != '\n') {
        scanf("%f", &operand);
        switch (operator) {
            case '+':
                total += operand;
                break;
            case '-':
                total -= operand;
                break;
            case '*':
                total *= operand;
                break;
            case '/':
                total /= operand;
                break;
        }
        printf("Value of operator: %c\n", operator);
        printf("Operand: %f\n", operand);
    }

    printf("Value of expression: %f\n", total);

两次 printf 调用用于测试。输入:“1 + 5 + 9\n”导致:

Value of operator: +
Operand: 5.000000
Value of operator:  
Operand: 5.000000
Value of operator:  
Operand: 9.000000
Value of expression: 6.000000

所以,程序似乎是这样的: scanf() 将 1 读入 'total',将其后的 space 与格式字符串中的 space 配对,遇到 '+',然后将其放回缓冲区并 returns.

然后:

循环 1 - getchar() 读取剩余的“+”并将其放入 'operator'。 scanf() 读取 5,遇到 space,将其放回缓冲区,然后 returns.

循环 2 - getchar() 读取剩余的 ' ',并将其放入 'operator' scanf() 遇到 '+' 并立即 returns 并将其放回缓冲区。

这里的内容与我的理解不符。在循环 3 开始时,getchar() 应该遇到 '+' 并将其存储到 'operator' 中。相反,它被完全跳过了,对我来说毫无意义。

此处跳过空格:while ((operator = nextchar()) != '\n') 而不是 getchar()

其中 nextchar() 可以是

int nextchar(void) {
    int ch;
    do ch = getchar(); while (ch == ' '); // assume '\n' shows up before EOF
    return ch;
}

在第一个循环之后,输入缓冲区包含 " + 9\n"

因此 getchar 将读取 space 并且输入缓冲区然后保存“+ 9\n”

然后scanf("%f", &operand);会先读取对float有效的+。因此它继续并读取下一个 space,它在 + 之后对浮点数无效,因此转换失败。 space 留在输入缓冲区中,但已经读取的 + 无法返回,因此它丢失了。

这在标准中有描述(引用 N1570):

An input item is read from the stream, unless the specification includes an n specifier. An input item is defined as the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence. 285) The first character, if any, after the input item remains unread.

注释 285 说:

  1. fscanf pushes back at most one input character onto the input stream.

简而言之:

当使用数字转换说明符扫描 + 后跟 space(即“+”)时,将导致匹配失败,并且 + 将被静默地从输入。

针对您的情况,一个简单的解决方案可能是:

while ((operator = getchar()) != '\n') {
    if (operator == ' ') continue;

您需要检查 scanf 的返回值,因为它 returns 它能够读取的格式说明符的数量。您仍然需要知道是否输入了 float。在任何一种情况下,您都需要做不同的事情......如果运算符和数字的顺序不合适,可能会发出语法错误信号。

还考虑将 +3.5 扫描为浮点数或运算符 + 后跟无符号浮点数的可能性。