What is the purpose of storing the content in memory before printing it?
In your example, there isn't much of a point. The data being read from std::cin
is being sent directly to std::cout
to be displayed on the console. Generally, the only reasons you'd want to store the data in the program memory before printing it is if you want to modify the data or check properties of the data and take certain actions based on those properties.
It should be noted that while this is a common example, the use of while (!eof())
is the incorrect way to check the validity of the stream before reading data. This method checks the stream before the input is read, which can lead to undefined behavior if invalid data is read and subsequently used. The normal way to read data is to check the validity of the stream after performing the read. For example, in your program this would be changed to:
while (f >> a)
{
std::cout << a << std::endl;
}
After the read is performed, the stream will be converted to a boolean. It will return true
or false
depending on the validity of the stream. If the stream read the end-of-file (EOF) character then that would be a failed read and the stream will return false
.
What is the point of
char a[80];
...
f >> a;
cout << a << endl;
when we could just do
cout << f << endl;
First, cout << f
will not do what you expect. The stream insertion operator (operator<<()
) is overloaded for certain types. f
is of type std::ifstream
- a type for which this operator is not overloaded. Pre-C++11 C++ IOStreams contained a conversion to void*
so that they could be used in boolean contexts. The stream insertion operator is overloaded for pointers to void
, so the output you would get is not something you'd expect. As of C++11 you'd get a compiler error that no operator overload could be found for that type.
There is, however, an overload for std::streambuf*
, a pointer an IOStreams buffer. Each stream has a buffer that stores and maintains characters from the source or sink. The overload for this operator reads data from the buffer and sends it to its own buffer, so you can do something like this:
std::cout << f.rdbuf();
rdbuf()
returns a pointer to the stream's buffer.
While this is an effective use of the stream's capabilities, the data is still being stored in the buffer of std::cout
. Streams are buffered and data sent into the source or sink are consigned to a buffer where it waits until the buffer is flushed. You can use std::nounitbuf
to unbuffer std::cout
in order to write directly to the external device:
std::cout << std::nounitbuf
<< f.rdbuf();
For a simple example with a small file, buffering really isn't needed. If you have a very large file then buffering is very useful as the program doesn't have to make a system call for each character being inserted.