2015-03-27 21 views
11

Nếu tôi nhập từ "Hello World" vào luồng nhập chuẩn, chương trình này sẽ in ra các ký hiệu hộp lạ thay vì "Hello World" dự kiến ​​trở lại đầu ra tiêu chuẩn.putchar() đầu ra lạ, tại sao điều này lại xảy ra?

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

Tôi biết cách khắc phục sự cố. Nhưng tại sao dòng mã này không chính xác?

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

Bạn có thể tìm thấy danh sách các toán tử ưu tiên tại đây theo cách: http: //en.cp preferences.com/w/c/language/operator_precedence. (Cảm thấy một chút ngớ ngẩn đăng một câu trả lời với triệu mà chỉ cần đến in: D) – Ulfalizer

+0

Thú vị, tôi không nghĩ rằng ưu tiên nhà điều hành trong C sẽ khác với C# và Java. – zxgear

+0

Nếu bạn đang nghĩ về trường hợp cụ thể này, thì nó có vẻ giống nhau trong Java và C#. Sẽ rất tệ nếu 'x_eq_y = x == y' được hiểu là' (x_eq_y = x) == y', như một ví dụ ngớ ngẩn. C có một số tiền lệ đáng lo ngại mặc dù (đã được thừa nhận bởi các tác giả như là một sai lầm, nhưng vẫn còn được mô phỏng bởi các ngôn ngữ khác để tương thích). Ví dụ: 'x == y << z' giống với' x == (y << z) 'như bạn mong đợi, trong khi' x == y & z' giống với '(x = = y) & z'. – Ulfalizer

Trả lời

30

(ch = getchar() != '\n') nên được viết lại như

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

!= liên kết chặt chẽ hơn = trong C operator precedence table. Nhà điều hành không được đặt hàng từ trái sang phải (đọc hướng của tiếng Anh) như người ta có thể mong đợi. Ví dụ: kết quả của 2 + 3 * 517không25. Điều này là do * sẽ được thực hiện trước khi thực hiện +, bởi vì toán tử * có mức ưu tiên cao hơn so với toán tử +.

Vì vậy, khi bạn viết một cái gì đó giống như

ch = getchar() != '\n' 

Bạn mong đợi nó sẽ tương đương với: (ch = getchar()) != '\n'

Nhưng trên thực tế nó tương đương với: ch = (getchar() != '\n')

Vì kết quả của !=true hoặc false, bạn thấy ký tự \001 trên màn hình. Tôi tin rằng \001 xuất hiện dưới dạng hộp trên hệ thống của bạn.


1: Nhân vật \001 có thể xuất hiện như một hộp hoặc dấu chấm hoặc một số nhân vật lạ hoặc nó có thể không xuất hiện trong đầu ra ở tất cả.

+0

Trong tham chiếu đến 'Ví dụ kết quả của 2 + 3 * 5 là 17 và không phải là 25' .... Đây là một câu trả lời tuyệt vời nhưng, Nếu nó là' 2 * 3 + 5', nó vẫn sẽ được đánh giá là '11 'và không phải là' 16' .. Nó có liên quan đến toán tử '*' được ưu tiên hơn '+' so với đánh giá từ phải sang trái. Một số tân binh sẽ làm điều này sai. \ – WedaPashi

+0

@WedaPashi Cảm ơn lời nhận xét hữu ích của bạn, tôi sẽ cập nhật câu trả lời của tôi cho phù hợp. –

+1

Theo logic chương trình, \ 000 sẽ được nhìn thấy "không bao giờ", không phải "hiếm khi". Ngay khi gethcar() trả về '\ n', ch được gán 0 và thân loob không được thi hành. –

9

Bạn cần phải nhận thức được operator precedence - toán tử so sánh như != có một ưu tiên cao hơn chuyển nhượng (=). Sử dụng dấu ngoặc đơn để thực thi các hành vi cần thiết, tức là thay đổi:

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

tới:

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


Phụ Lục: hãy chắc chắn hãy chú ý của lời khuyên từ @TomGoodfellow trong một câu trả lời riêng biệt dưới đây - sử dụng một trình biên dịch tốt với các cảnh báo được kích hoạt (ví dụ: gcc -Wall) sẽ cảnh báo bạn về vấn đề này ngay lập tức.

5

Bởi vì bạn cần phải viết nó như while ((ch = getchar()) != '\n')

+1

Mặc dù bạn rất đúng, bạn nên thêm một số mô tả về những gì, cách thức và lý do tại sao trong câu trả lời của bạn để làm cho nó trở thành một điều tuyệt vời. Chúc mừng !! :-) –

12

Và như một câu trả lời hơi meta-ish, sửa chữa tổng thể luôn được biên soạn với các cảnh báo được kích hoạt:

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

Hoặc tốt hơn chưa thử kêu vang, mà cảnh báo theo mặc định và thường cung cấp thông báo chẩn đoán tốt hơn:

$ 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. 
Các vấn đề liên quan