Q:

putchar() weird output, why is this happening?

If I type the words "Hello World" into the standard input stream, this program will print out weird box symbols instead of the expected "Hello World" back into standard output.
#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');
}

I am aware of how to fix the problem. But why is this line of code incorrect?
while (ch = getchar() != '\n')

A:

(ch = getchar() != '\n') should be rewritten as
((ch = getchar()) != '\n')

Because != binds tighter than = in C operator precedence table. Operator are not ordered from left to right (reading direction of english) as one might expect. For example result of 2 + 3 * 5 is 17 and not 25. This is because * will be performed before performing +, because * operator has more precedence than + operator.
So when you write something like
ch = getchar() != '\n'

You expect it to be equivalent to: (ch = getchar()) != '\n'
But actually it is equivalent to: ch = (getchar() != '\n')
Because the result of != is either true or false, you see character \001 on screen. I believe \001 appears as boxes1 on your system.

1: Character \001 may appear as a box or dot or some wierd character or it may not appear in output at all.

A:

And as a slightly meta-ish answer, the overarching fix is always compiling with warnings enabled:
$ 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]
 }
 ^

Or better yet try clang, which warns by default and generally gives better diagnostic messages:
$ 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.

A:

You need to be aware of operator precedence - comparison operators such as != have a higher precedence than assignment (=). Use parentheses to enforce the required behaviour, i.e. change:
while (ch = getchar() != '\n')

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

Addendum: be sure to take heed of the advice from @TomGoodfellow in a separate answer below - using a decent compiler with warnings enabled (e.g. gcc -Wall) would have alerted you to this problem immediately.

