【问题标题】:putchar() weird output, why is this happening?putchar() 奇怪的输出,为什么会这样?
【发布时间】:2015-05-31 10:58:22
【问题描述】:

如果我在标准输入流中输入单词“Hello World”,该程序将打印出奇怪的框符号而不是预期的“Hello World”回到标准输出中。

#include <stdio.h>

int main(void)
{
    // print out all characters from the stream until '/n' character is found
    int ch;
    while (ch = getchar() != '\n')
    {
        putchar(ch);
    }
    putchar('\n');
}

我知道如何解决这个问题。但是为什么这行代码不正确呢?

while (ch = getchar() != '\n')

【问题讨论】:

  • 你可以顺便在这里找到一个运算符优先级列表:en.cppreference.com/w/c/language/operator_precedence。 (感觉有点傻用刚刚进来的百万张贴答案。:D)
  • 有趣,我没想到 C 中的运算符优先级与 C# 和 Java 不同。
  • 如果您正在考虑这种特殊情况,那么它在 Java 和 C# 中似乎是相同的。如果x_eq_y = x == y 被解释为(x_eq_y = x) == y,那就太糟糕了,作为一个愚蠢的例子。尽管 C 有一些不稳定的优先级(作者已承认这是一个错误,但仍被其他语言模仿以实现兼容性)。例如,x == y &lt;&lt; z 与您期望的 x == (y &lt;&lt; z) 相同,而 x == y &amp; z(x == y) &amp; z 相同。
  • 在 Java 中试试这个:(fooBoolean = fooInteger == barInteger)。 == 运算符的优先级高于 = 运算符。
  • @JohnH 在任何情况下,Java 和 C# 中的运算符优先级都与 C 不同。不是反过来(因为 C 更老)。此外,为了在 C 中的优先级不再失败,您必须记住乘法和除法的优先级高于加法和减法。其他所有内容都需要括号。

标签: c io operator-precedence getchar putchar


【解决方案1】:

(ch = getchar() != '\n') 应该改写为

((ch = getchar()) != '\n')

因为!=C operator precedence table 中的绑定比= 更紧密。正如人们所期望的那样,运算符的顺序不是从左到右(英语的阅读方向)。例如 2 + 3 * 5 的结果是 17not 25。这是因为* 将在执行+ 之前执行,因为* 运算符的优先级高于+ 运算符。

所以当你写类似的东西时

ch = getchar() != '\n'

你期望它等同于(ch = getchar()) != '\n'

但实际上相当于ch = (getchar() != '\n')

因为!= 的结果是truefalse,所以您会在屏幕上看到字符\001。我相信\001 在您的系统上显示为框1


1:字符\001 可能显示为一个框或点或一些奇怪的字符,或者它可能根本不会出现在输出中。

【讨论】:

  • 参考For example result of 2 + 3 * 5 is 17 and not 25..这是一个很好的答案,但是如果是2 * 3 + 5,它仍然会被评估为11而不是16..它与 * 运算符优先于 + 比从右到左评估有关。有些菜鸟会错误地理解这一点。\
  • @WedaPashi 感谢您的有用评论,我会相应地更新我的答案。
  • 按照程序逻辑,\000 将被视为“从不”,而不是“很少”。一旦 gethcar() 返回 '\n',ch 就被赋值为 0,并且不会执行 lob 体。
【解决方案2】:

因为你需要写成while ((ch = getchar()) != '\n')

【讨论】:

  • 虽然您说得非常正确,但您应该在您的答案中添加一些关于什么、如何以及为什么的描述,以使其成为一个很棒的答案。干杯!! :-)
【解决方案3】:

您需要注意operator precedence - 比较运算符(如!=)的优先级高于赋值(=)。使用括号强制执行所需的行为,即更改:

while (ch = getchar() != '\n')

到:

while ((ch = getchar()) != '\n')


附录:请务必注意@TomGoodfellow 在下面的单独答案中的建议 - 使用启用警告的体面编译器(例如gcc -Wall)会立即提醒您这个问题。

【讨论】:

    【解决方案4】:

    作为一个稍微有点元的答案,总体修复总是在启用警告的情况下进行编译:

    $ gcc t.c -Wall
    t.c: In function ‘main’:
    t.c:7:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
         while (ch = getchar() != '\n')
         ^
    t.c:12:1: warning: control reaches end of non-void function [-Wreturn-type]
     }
     ^
    

    或者更好的是尝试 clang,默认情况下会发出警告,并且通常会提供更好的诊断信息:

    $ clang t.c
    t.c:7:15: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
        while (ch = getchar() != '\n')
               ~~~^~~~~~~~~~~~~~~~~~~
    t.c:7:15: note: place parentheses around the assignment to silence this warning
        while (ch = getchar() != '\n')
              ^
               (                     )
    t.c:7:15: note: use '==' to turn this assignment into an equality comparison
        while (ch = getchar() != '\n')
                  ^
                  ==
    1 warning generated.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-06
      • 2020-04-11
      相关资源
      最近更新 更多