C++/File Handling in C++
Expert: Ralph McArdell - 9/5/2007
QuestionIt's a file handling program in C++.
while executing the program below I got the last number printed twice.My required output is supposed to be twice as if I take input as 10 and 20 then output is supposed to be 10 and 20 only but I got 102020 as the output.
Plz specify the reason :
#include<fstream.h>
#include<conio.h>
void main()
{
ofstream fout("marks.dat");
int m;
cin>>m;
fout<<m<<"\n";
cin>>m;
fout<<m;
fout.close();
ifstream fin("marks.dat");
while(fin)
{
fin>>m;
cout<<m;
}
fin.close();
}
AnswerFirst, why are you using pre-standard and non-standard headers?
The standard C++ header is <fstream> _not_ <fstream.h> and <conio.h> is Microsoft specific if I remember correctly. Also I see no need for including conio.h anyway, as far as I can tell you are not using anything it defines or declares. Note that the C++ standard was published in 1998 and most, if not all compilers with standard C++ libraries released since then support the new header names (i.e. without a .h extension) - including quite old compilers such as MS VC++ 6.0. Oh and you need to include <iostream> to use cin and cout (in fact they are properly named std::cin and std::cout in standard C++ as most standard library names are in the std namespace - same for std::ofstream and std::ifstream).
Secondly the:
void main()
{
}
Form of main is a non-standard Microsoft perversion. The standard forms are:
int main()
{
}
And:
int main(int argc, char * argv[])
{
}
For these forms MS VC6.0 and before requires that an explicit return statement is used, however the standard permits for main only that it can be omitted, in which case it is as if there were a return 0. MS VC6.0 and earlier requires void to be used if there is no return value, which as noted is non-standard.
Anyhow your problem is not so much that you have an i/o problem than that you have a logic problem.
In the loop:
while ( fin )
{
fin >> m;
cout << m;
}
Let us run through what happens:
Initially if fin opened OK the file read position is at the beginning of the file. So the first time through the first number you entered, 10, is read and output. All well and good.
The stream is in a good state so the loop continues. This time the second number, 20, is read and output. Again the stream is in a good state so the loop continues.
Oh dear! This time there is no more data in the file and the read operation from fin into m fails, thus m is not updated and retains its previous value. You do not check that the read operation succeeded before using the value supposedly read in so the value of m, 20, is output again. The fin stream is no longer in a good state; it is in the end of file (eof) state; so the loop terminates.
The fix is to add an additional check for fin being good inside the loop:
while ( fin )
{
fin >> m;
if ( fin )
{
cout << m;
}
}
Whilst we are on the topic of checking stream states although the presence of the above loop checks that fin is not read from if it is not open the same cannot be said of trying to write to fout if it fails to open: you just assume it does open OK - this may not be true. You may not have access to write to the location or file or you may not have specified a valid path (should be OK in this case as no path is given!), or the file system may have no room for further data etc. You can check the file stream is open using the is_open operation:
if ( ! fout.is_open() )
{
std::cerr << "Unable to open file for writing." << std::endl;
return 1; // non-zero returns from main often indicate an error
}
In fact if opening the file fails then the stream failbit should be set if the stream class is C++ standards conforming so we could also write:
if ( !fout )
...
Lastly, you usually do not need to call close explicitly on a file. In this case you do if fout is open so that the file may be re-opened for reading as a file usually may only have one writer and no other readers or writers, but may have many readers and no writers. However you do not need to explicitly call close for fin - when a stream object is destroyed it will be closed if a file is open on it. In fact this is better for fin, as you should not call close if fin failed to open the file - how can you close a non-open stream?
Note that local objects such as fout and fin are destroyed when they go out of scope. In this case that is at the closing brace of main. Hence without the explicit call to close the "marks.dat" file would still be open for writing on fout when you open it for reading on fin - which should fail. However fout is closed at the end of the program as it is, so removing the line:
fin.close();
would mean that fin is closed at the same point in the procedure, as the following line is the closing brace to main, where fout and fin are destroyed and files they hold open are closed.
Hope this helps.