10

如果我在标准输入流中键入单词“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')
4

4 回答 4

29

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

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

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

所以当你写类似的东西时

ch = getchar() != '\n'

您希望它等同于(ch = getchar()) != '\n'

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

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


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

于 2015-03-27T07:15:30.913 回答
12

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

$ 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.
于 2015-03-27T11:34:56.977 回答
8

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

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

至:

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


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

于 2015-03-27T07:15:21.253 回答
5

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

于 2015-03-27T07:15:35.000 回答