Putchar() странный вывод, почему это происходит?

Если я ввожу слова "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')

Ответ 1

(ch = getchar() != '\n') следует переписать как

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

Потому что != связывается более жестко, чем = в таблица приоритетов оператора C. Оператор не упорядочен слева направо (направление чтения по-английски), как и следовало ожидать. Например, результат 2 + 3 * 5 равен 17 и не 25. Это связано с тем, что * будет выполняться перед выполнением +, потому что оператор * имеет более высокий приоритет, чем +.

Итак, когда вы пишете что-то вроде

ch = getchar() != '\n'

Вы ожидаете, что он будет эквивалентен: (ch = getchar()) != '\n'

Но на самом деле это эквивалентно: ch = (getchar() != '\n')

Потому что результатом != является либо true, либо false, вы видите символ \001 на экране. Я полагаю, что \001 появляется в виде ящиков 1 в вашей системе.


1: Символ \001 может отображаться как поле или точка или какой-то странный символ, или он вообще не может отображаться на выходе.

Ответ 2

И как немного мета-иш-ответ, всеобъемлющее исправление всегда компилируется с включенными предупреждениями:

$ 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.

Ответ 3

Вам нужно знать приоритет оператора - операторы сравнения, такие как !=, имеют более высокий приоритет, чем назначение (=). Используйте круглые скобки для принудительного выполнения требуемого поведения, т.е. Изменения:

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

в

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


Добавление: обязательно прислушайтесь к советам @TomGoodfellow в отдельном ответе ниже - использование достойного компилятора с включенными предупреждениями (например, gcc -Wall) немедленно предупредило вас об этой проблеме.

Ответ 4

Потому что вам нужно записать его как while ((ch = getchar()) != '\n')