Dòng trên cùng: Với việc xử lý đúng khoảng trắng, sau đây là cách eof
sử dụng (và thậm chí, đáng tin cậy hơn so fail()
với kiểm tra lỗi):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
( Cảm ơn Tony D về gợi ý để làm nổi bật câu trả lời. Xem bình luận của anh ấy bên dưới để biết ví dụ về lý do tại sao điều này mạnh mẽ hơn. )
Đối số chính chống lại việc sử dụng eof()
dường như đang thiếu một sự tinh tế quan trọng về vai trò của khoảng trắng. Đề xuất của tôi là, kiểm tra eof()
rõ ràng không chỉ không phải là " luôn luôn sai " - mà dường như là một ý kiến quan trọng trong các chủ đề SO tương tự này - nhưng với việc xử lý không gian trắng đúng cách, nó cung cấp cho sạch hơn và đáng tin cậy hơn xử lý lỗi và là giải pháp luôn luôn đúng (mặc dù, không nhất thiết là khó nhất).
Để tóm tắt những gì đang được đề xuất là lệnh chấm dứt và đọc "đúng" như sau:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
Thất bại do nỗ lực đọc vượt quá eof được coi là điều kiện chấm dứt. Điều này có nghĩa là không có cách dễ dàng để phân biệt giữa một luồng thành công và một luồng thực sự thất bại vì những lý do khác ngoài eof. Thực hiện các luồng sau:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
chấm dứt với một bộ failbit
cho cả ba đầu vào. Trong thứ nhất và thứ ba, eofbit
cũng được thiết lập. Vì vậy, qua vòng lặp, người ta cần logic bổ sung rất xấu để phân biệt đầu vào thích hợp (thứ 1) với đầu vào không phù hợp (thứ 2 và thứ 3).
Trong khi đó, hãy thực hiện như sau:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Ở đây, in.fail()
xác minh rằng miễn là có một cái gì đó để đọc, đó là một cái chính xác. Mục đích của nó không phải là một terminator vòng lặp đơn thuần.
Cho đến nay là tốt, nhưng điều gì xảy ra nếu có không gian kéo dài trong luồng - điều gì nghe có vẻ như mối quan tâm chính chống lại eof()
như kẻ hủy diệt ?
Chúng tôi không cần phải từ bỏ việc xử lý lỗi của mình; Chỉ cần ăn hết khoảng trắng:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
std::ws
bỏ qua mọi khoảng trống tiềm năng (không hoặc nhiều hơn) trong luồng trong khi đặt eofbit
và không phải làfailbit
. Vì vậy, in.fail()
hoạt động như mong đợi, miễn là có ít nhất một dữ liệu để đọc. Nếu các luồng trống hoàn toàn cũng được chấp nhận, thì dạng chính xác là:
while( !(in>>ws).eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
/* this will never fire if the eof is reached cleanly */
// now use data
}
Tóm tắt: Một cấu trúc đúng while(!eof)
không chỉ có thể và không sai, mà còn cho phép dữ liệu được định vị trong phạm vi và cung cấp sự phân tách kiểm tra lỗi rõ ràng hơn từ doanh nghiệp như bình thường. Điều đó đang được nói, đặc biệt while(!fail)
là một thành ngữ phổ biến và ngắn gọn hơn, và có thể được ưa thích trong các tình huống đơn giản (dữ liệu trên mỗi loại đọc).
scanf(...) != EOF
Sẽ không hoạt động trong C, bởi vìscanf
trả về số lượng các trường được phân tích và gán thành công. Tình trạng chính xác làscanf(...) < n
ở đâun
là số lĩnh vực trong chuỗi định dạng.