eof() bad practice?
You can use eof
to test for the exact condition it reports - whether you have attempted to read past end of file. You cannot use it to test whether there's more input to read, or whether reading succeeded, which are more common tests.
Wrong:
while (!cin.eof()) {
cin >> foo;
}
Correct:
if (!(cin >> foo)) {
if (cin.eof()) {
cout << "read failed due to EOF\n";
} else {
cout << "read failed due to something other than EOF\n";
}
}
Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?
Because iostream::eof
will only return true
after reading the end of the stream. It does not indicate, that the next read will be the end of the stream.
Consider this (and assume then next read will be at the end of the stream):
while(!inStream.eof()){
int data;
// yay, not end of stream yet, now read ...
inStream >> data;
// oh crap, now we read the end and *only* now the eof bit will be set (as well as the fail bit)
// do stuff with (now uninitialized) data
}
Against this:
int data;
while(inStream >> data){
// when we land here, we can be sure that the read was successful.
// if it wasn't, the returned stream from operator>> would be converted to false
// and the loop wouldn't even be entered
// do stuff with correctly initialized data (hopefully)
}
And on your second question: Because
if(scanf("...",...)!=EOF)
is the same as
if(!(inStream >> data).eof())
and not the same as
if(!inStream.eof())
inFile >> data
Why is eof() never returning true?
The problem with your use of std::istream::get
is that it doesn't consume the delimiter. It will work fine for the first call, but then the next call will immediately see the newline left over from the previous call, and not read anything.
If you want to read lines, either use std::istream::getline
(if you persist on using character arrays) or std::getline
with std::string
which is what I recommend.
You also don't need explicit eof
checks, instead rely on the fact that all functions returns (a reference to) the stream and that the streams can be used directly in conditions, so do e.g.
if (!std::getline(...))
// end of file or error
why does eof() not work as I expect?
The problem is that when extracting symbols for 45,it tries to extract symbol after '5' (to check if number continues further) and sees end of file, setting eofbit
. This makes in.good()
test to fail. Suggestions:
while (!in.eof()){
in >> i;
if ( in ) { //Not .good(), just conversion to bool
Or
while (!in.eof()){
if ( in >> i; ) { //both extraction and checking in same operation
Remember, .good()
is not the same as checking stream state. .good()
is telling if stream ready for further input. Bool conversion does ! .fail()
and checks if last operation was executed succesfully
End of File (EOF)
One way is to check wether the first input operation succeeds or not:
#include <iostream>
int main() {
double number;
if(std::cin >> number)
{
while (std::cin >> number);
std::cout << number;
}
else
{
std::cout << "There is no number :(";
}
}
Few things I changed here:
- removed
using namespace std;
, it's considered bad parctice - a
while
is better suited for this task than a half-emptyfor
And of course this can be generalized to any std::basic_istream
.
Why is failbit set when I enter EOF?
eofbit
is set when a read operation encounters EOF while reading data into the stream's buffer. The data hasn't been processed yet.
failbit
is set when the requested data fails to be extracted from the buffer, such as when reading an integer with operator>>
. While waiting for digits to arrive, EOF could occur. eofbit
alone is not enough to enter an error state, as there may be usable data in the buffer.
So, for example, imagine a while (cin >> num)
loop is used and the user enters 123<Ctrl-Z>
.
on the 1st iteration,
operator>>
reads1
,2
,3
into the buffer, then encounters Ctrl-Z, so it setseofbit
and stops reading.123
is then extracted from the buffer intonum
and the operator exits. At this point, the stream is not yet in an error state. When the stream'sbool
conversion is evaluated bywhile
, it returns true, allowing thewhile
body to be entered so it can processnum
.on the next iteration,
operator>>
seeseofbit
is set, preventing further reading. There is nothing left in the buffer to extract intonum
, so the operator setsfailbit
and exits. The stream is now in an error state. When the stream'sbool
conversion is evaluated bywhile
, it returns false, breaking thewhile
loop.
using eof on C++
You're pretty close, but probably being influenced a bit more by your Pascal background than is ideal. What you probably want is more like:
#include<iostream>
using namespace std; // Bad idea, but I'll leave it for now.
int main()
{
int k,sum = 0; // sum needs to be initialized.
while (cin >> k)
{
sum += k; // `sum = sum + k;`, is legal but quite foreign to C or C++.
}
cout << sum<<endl;
}
Alternatively, C++ can treat a file roughly like a sequential container, and work with it about like it would any other container:
int main() {
int sum = std::accumulate(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
0); // starting value
std::cout << sum << "\n";
return 0;
}
Why does std::fstream set the EOF bit the way it does?
Because this way it can detect EOF
without knowing how large the file is. All it has to do is simply attempt to read and if the read is short (but not an error), then you have reached the end of the file.
This mirrors the functionality of the read
system call, which file IO typically ends up calling (win32 stuff may call ReadFile
but I believe that the functionality is similar).
From the read
manpage "RETURN VALUE" section (emphasis added):
On success, the number of bytes read
is returned (zero indicates end of
file), and the file position is
advanced by this number. It is not an
error if this number is smaller than
the number of bytes requested; this
may happen for example because fewer
bytes are actually available right now
(maybe because we were close to
end-of-file, or because we are reading
from a pipe, or from a terminal), or
because read() was interrupted by a
signal. On error, -1 is returned, and
errno is set appropriately. In this
case it is left unspecified whether
the file position (if any) changes.
BTW: a good way to write what you wanted would be like this:
T something;
while(file.read(something, sizeof(something))) {
// process your 'something'
}
this works because file.read
(like many members of iostream) return a reference to the iostream itself. All of which have an operator overloaded to allow testing the stream state. Similarly to read from std::cin
, while(std::cin >> x) { ... }
works as well.
EDIT: you should know that testing vs. fail can be equally wrong for the same reason. From the page you linked to fail()
returns if the previous operation failed. Which means you need to perform a read or other relevant operation before testing it.
Related Topics
Undefined Behavior and Sequence Points Reloaded
Using Opencv and Svm With Images
Is There a Replacement For Unistd.H For Windows (Visual C)
What Is the Fastest Way to Transpose a Matrix in C++
How Does #Include ≪Bits/Stdc++.H≫ Work in C++
Why Are Unnamed Namespaces Used and What Are Their Benefits
How to Use Break to Exit Multiple Nested 'For' Loops
How to Sort a Vector of Pairs Based on the Second Element of the Pair
How to Get Rid of 'Deprecated Conversion from String Constant to 'Char*'' Warnings in Gcc
How to Make Cmake Output into a 'Bin' Dir
Detecting Superfluous #Includes in C/C++
Global Memory Management in C++ in Stack or Heap
C++11 Reverse Range-Based For-Loop
Are Flexible Array Members Valid in C++
Where Exactly Does C++ Standard Say Dereferencing an Uninitialized Pointer Is Undefined Behavior