2010-06-04 98 views
10

Có lẽ một câu trả lời cực kỳ đơn giản cho câu hỏi cực kỳ đơn giản này:Sử dụng scanf trong một thời gian vòng lặp

tôi đang đọc "C Primer Plus" bởi Pratta và ông tiếp tục sử dụng các ví dụ

while (scanf("%d", &num) == 1)... 

Là == 1 thực sự cần thiết? Có vẻ như người ta chỉ có thể viết:

while (scanf("%d", &num)) 

Có vẻ như kiểm tra bình đẳng là không cần thiết vì scanf trả về số lượng đối tượng đã đọc và 1 sẽ làm cho vòng lặp while đúng. Có phải lý do để đảm bảo rằng số lượng các phần tử đọc chính xác là 1 hoặc là điều này hoàn toàn không cần thiết?

+0

Vâng, trông khá dư thừa đối với tôi ... – tzaman

Trả lời

22

Trong C, 0 được đánh giá là false và mọi thứ khác là true. Vì vậy, nếu scanf trả về EOF, đó là một giá trị âm, vòng lặp sẽ đánh giá là đúng, đó không phải là những gì bạn muốn.

+0

EOF là yếu tố quan trọng ở đây, bắt thú vị. –

3

Bạn đã hiểu mã C chính xác.

Đôi khi lý do để kiểm tra số lượng mục được đọc là ai đó muốn đảm bảo rằng tất cả các mục đã được đọc thay vì scanf bỏ sớm khi đầu vào không khớp với loại mong muốn. Trong trường hợp này, nó không quan trọng.

Thông thường scanf là một lựa chọn kém chức năng vì nó không đáp ứng nhu cầu của đầu vào tương tác từ người dùng. Thông thường, sự kết hợp giữa fgets và sscanf mang lại kết quả tốt hơn. Trong trường hợp này, nó không quan trọng.

Nếu các chương sau giải thích lý do tại sao một số loại thực tiễn mã hóa tốt hơn ví dụ tầm thường này, tốt. Nhưng nếu không, bạn nên đổ sách bạn đang đọc.

Mặt khác, mã thay thế của bạn không chính xác là một thay thế. Nếu scanf trả về -1 thì vòng lặp while của bạn sẽ thực thi.

+0

Sai, xem các câu trả lời khác. Nó trả về -1 khi xảy ra lỗi EOF hoặc lỗi đọc. –

+2

"Sai, xem các câu trả lời khác". - bạn có nghĩa là sai, xem câu trả lời của riêng tôi, bởi vì đó là lý do tại sao tôi đã viết "Nếu scanf trả về -1 thì vòng lặp while của bạn sẽ thực thi." –

8

scanf trả về giá trị EOF (là -1) ở cuối tệp, vòng lặp được viết là chính xác. Nó chạy miễn là đầu vào chứa văn bản khớp với %d và dừng ở đầu hoặc cuối tập tin đầu tiên.

Nó đã có rõ ràng trong nháy mắt nếu scanf mong đợi nhiều hơn một đầu vào ....

while (scanf("%d %d", &x, &y)==2) { ... } 

sẽ thoát khỏi vòng lặp khi lần đầu tiên nó đã không thể để phù hợp với hai giá trị, hoặc do kết thúc của file cuối của tập tin (scanf lợi nhuận EOF (đó là -1)) hoặc trên đầu vào phù hợp với lỗi (ví dụ như đầu vào xyzzy 42 không phù hợp %d %d nên scanf điểm dừng trên sự thất bại đầu tiên và trả về 0 mà không cần viết cho một trong hai x hoặc y) khi nó trả về một số giá trị nhỏ hơn 2.

Tất nhiên, scanfkhông phải bạn của bạn khi phân tích cú pháp đầu vào thực từ người bình thường. Có rất nhiều cạm bẫy trong việc xử lý các trường hợp lỗi.

Edit: Sửa một lỗi: scanf lợi nhuận EOF vào cuối tập tin, hoặc một số nguyên không âm đếm số lượng các biến nó thiết lập thành công.

Điểm quan trọng là vì bất kỳ giá trị khác 0 là TRUE trong C, không kiểm tra giá trị trả về chính xác trong vòng lặp như thế này có thể dễ dẫn đến hành vi không mong muốn.Cụ thể, while(scanf(...)) là một vòng lặp vô hạn trừ khi nó gặp văn bản đầu vào không thể chuyển đổi theo định dạng của nó.

Và tôi không thể nhấn mạnh đủ mạnh rằng scanfkhông phải bạn của bạn. Một sự kết hợp của fgetssscanf có thể là đủ cho một số phân tích cú pháp đơn giản, nhưng thậm chí sau đó nó dễ dàng bị áp đảo bởi các trường hợp cạnh và lỗi.

1

Mặc dù bạn chính xác nhưng điều đó không thực sự cần thiết, một số người thích nó vì nhiều lý do.

Đầu tiên, bằng cách so sánh 1 giá trị này sẽ trở thành giá trị boolean rõ ràng (đúng hoặc sai). Nếu không có so sánh, bạn đang thử nghiệm trên một số nguyên, đó là hợp lệ trong C, nhưng không phải trong các ngôn ngữ sau này (như C#). Thứ hai, một số người sẽ đọc phiên bản thứ hai về thời gian ([hàm]), thay vì trong khi ([giá trị trả về]), và bị lẫn lộn trong giây lát bằng cách thử nghiệm hàm, khi ý nghĩa rõ ràng là thử nghiệm giá trị trả lại.

Điều này hoàn toàn có thể là vấn đề sở thích cá nhân và theo như tôi quan tâm, cả hai đều hợp lệ.

1

Người ta có thể viết nó mà không có sự so sánh rõ ràng (xem câu trả lời của JRL), nhưng tại sao lại là một? Tôi muốn nói rằng các điều kiện so sánh ít chỉ nên được sử dụng với các giá trị có ngữ nghĩa boolean rõ ràng (ví dụ như một cuộc gọi isdigit()). Mọi thứ khác nên sử dụng so sánh rõ ràng. Trong trường hợp này (kết quả của scanf) ngữ nghĩa rõ ràng là không boolean, do đó so sánh rõ ràng là theo thứ tự.

Ngoài ra, so sánh thường có thể bỏ qua thường là so sánh với số không. Khi bạn cảm thấy thôi thúc bỏ qua sự so sánh với cái gì khác (như 1 trong trường hợp này) tốt hơn là nên suy nghĩ hai lần và chắc chắn rằng bạn biết bạn đang làm gì (xem câu trả lời của JRL).

Trong mọi trường hợp, khi so sánh có thể được bỏ qua một cách an toàn và bạn thực sự bỏ qua nó, ý nghĩa ngữ nghĩa thực tế của điều kiện vẫn giữ nguyên. Nó hoàn toàn không ảnh hưởng đến hiệu quả của mã kết quả, nếu đó là điều bạn đang lo lắng.

Các vấn đề liên quan