【问题标题】:getchar and scanf buffer issues. getchar not storing the correct valuegetchar 和 scanf 缓冲区问题。 getchar 没有存储正确的值
【发布时间】:2021-11-08 13:30:00
【问题描述】:

我对编程很陌生,我知道 scanf() 有一些怪癖。也就是说,当它检测到与其转换说明符不匹配的字符时,它会立即返回并将有问题的字符放回缓冲区,以便由另一个 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',将其后面的空格与格式字符串中的空格配对,遇到 '+',然后将其放回缓冲区并返回。

然后:

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

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

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

【问题讨论】:

  • 尝试逐句调试,看看发生了什么。
  • 总是检查函数调用的返回值,特别是库的返回值。

标签: c scanf getchar


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    在第一个循环之后,输入缓冲区保持“+ 9\n”

    所以getchar 将读取空间,然后输入缓冲区保存“+ 9\n”

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

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

    从流中读取输入项,除非规范包含 n 说明符。一个 输入项定义为输入字符的最长序列,不超过 任何指定的字段宽度,并且是匹配的输入序列,或者是匹配输入序列的前缀。 285) 输入项之后的第一个字符(如果有)仍然未读。

    注释 285 说:

    1. fscanf 最多将一个输入字符推回输入流中。

    简而言之:

    当使用数字转换说明符扫描后跟空格(即“+”)的+ 时,将导致匹配失败,+ 将从输入中静默删除。

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

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

    【讨论】:

    • 这很有意义。我忘了 %f 可以读取前缀。谢谢。
    【解决方案3】:

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

    nextchar() 可以是类似的东西

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-25
      • 1970-01-01
      相关资源
      最近更新 更多