2015-03-27 12 views
11

Se digito le parole "Hello World" nel flusso di input standard, questo programma stamperà i simboli di casella strani invece che l'atteso "Hello World" torna allo standard output.putchar() output strano, perché sta succedendo?

#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'); 
} 

Sono a conoscenza di come risolvere il problema. Ma perché questa riga di codice è errata?

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

Qui è possibile trovare un elenco di precedenze degli operatori: http: //en.cp preference.com/w/c/language/operator_precedence. (Mi sono sentito un po 'sciocco postando una risposta con il milione che è appena entrato.: D) – Ulfalizer

+0

Interessante, non pensavo che la precedenza degli operatori in C sarebbe stata diversa da C# e Java. – zxgear

+0

Se stai pensando a questo caso particolare, sembra che sia lo stesso in Java e C#. Sarebbe un male se 'x_eq_y = x == y' fosse interpretato come' (x_eq_y = x) == y', come un esempio sciocco. C ha comunque delle vistose precedenze (che sono state riconosciute dagli autori come un errore, ma sono ancora emulate da altri linguaggi per compatibilità). Ad esempio, 'x == y << z' è lo stesso di' x == (y << z) 'come ti aspetteresti, mentre' x == y & z' è lo stesso di '(x = = y) & z'. – Ulfalizer

risposta

30

(ch = getchar() != '\n') dovrebbe essere riscritta come

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

Perché != si lega più stretto di = in C operator precedence table. L'operatore non viene ordinato da sinistra a destra (direzione di lettura dell'inglese) come ci si potrebbe aspettare. Ad esempio, il risultato di 2 + 3 * 5 è 17 e non25. Questo perché * verrà eseguito prima di eseguire +, perché l'operatore * ha precedenza rispetto all'operatore +.

Quindi, quando si scrive qualcosa come

ch = getchar() != '\n' 

ci si aspetta che sia equivalente a: (ch = getchar()) != '\n'

ma in realtà è equivalente a: ch = (getchar() != '\n')

Poiché il risultato di != è true o false, si vede il carattere \001 sullo schermo. Credo che \001 appaia come scatole sul tuo sistema.


1: Character \001 può apparire come una scatola o punto o qualche personaggio strano o non possono apparire in uscita a tutti.

+0

In riferimento a 'Ad esempio il risultato di 2 + 3 * 5 è 17 e non 25' .... Questa è un'ottima risposta ma, se fosse stato' 2 * 3 + 5', sarebbe comunque valutato come '11 'e non come' 16' .. Ha a che fare con la precedenza dell'operatore '*' su '+' rispetto alla valutazione da destra a sinistra. Alcuni rookie lo prenderebbero male. \ – WedaPashi

+0

@WedaPashi Grazie per il tuo utile commento, aggiornerò la mia risposta di conseguenza. –

+1

Tramite la logica del programma, \ 000 verrà visualizzato "mai", non "raramente". Non appena gethcar() restituisce '\ n', ch viene assegnato a 0 e il corpo loob non viene eseguito. –

9

Devi essere a conoscenza di operator precedence - operatori di confronto, come != hanno una precedenza maggiore di assegnazione (=). Utilizzare le parentesi per far rispettare il comportamento richiesto, vale a dire il cambiamento:

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

a:

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


Addendum: essere sicuri di prendere attenzione dei consigli da @TomGoodfellow in una risposta separata al di sotto - utilizzando un un compilatore decente con avvisi abilitati (ad es. gcc -Wall) ti avrebbe avvisato immediatamente di questo problema.

5

perché è necessario scrivere come while ((ch = getchar()) != '\n')

+1

Mentre hai ragione, dovresti aggiungere qualche descrizione su cosa, come e perché nella tua risposta per renderlo un grande. Saluti !! :-) –

12

E come una risposta un po 'di meta-ish, la correzione generale è sempre la compilazione con avvisi abilitati:

$ 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] 
} 
^ 

O meglio ancora provare clang, che avvisa per impostazione predefinita e in genere fornisce messaggi diagnostici migliori:

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