Show Lecture.IOStreams as a slide show.
CS253 I/O Streams
Predefined Streams
There are four predefined streams. Don’t open or close them.
Just use them.
- cin: standard input
- cout: standard output (for normal output)
- cerr: standard error (for error output)
- clog: standard error (for error output)
cerr is unbuffered, clog is buffered.
Use cerr for error messages, clog if you use standard error
for logging purposes.
Formatted output:
The insertion operator, <<
, is used for output.
You may recognize it as the left shift operator. It’s that, too.
Isn’t operator overloading wonderful?
int i = 5<<4;
double d = 4.5;
char c = 'x';
const char *ccs = "My dog";
string s = " has fleas";
cout << i << ' ' << d << " " << c << "\n"
<< ccs << s << '\n';
80 4.5 x
My dog has fleas
How can you tell if <<
means bit shift or insertion?
If the left operand is an output stream (or the result of another insertion)
then it’s insertion.
endl demonstration
static int zero = 0;
cout << "Alpha" << '\n' << 1/zero << '\n';
SIGFPE: Floating point exception
static int zero = 0;
cout << "Beta" << '\n';
cout << 1/zero << '\n';
SIGFPE: Floating point exception
static int zero = 0;
cout << "Gamma" << endl;
cout << 1/zero << '\n';
Gamma
SIGFPE: Floating point exception
static int zero = 0;
cout << "Delta" << endl << 1/zero << '\n';
Delta
SIGFPE: Floating point exception
Division by zero is undefined behavior, so none of this is guaranteed.
endl
cout << "alpha\n";
cout << "beta" << endl;
cout << "gamma" << "\n";
cout << "delta" << '\n';
alpha
beta
gamma
delta
- Some C++ programmers think that endl and
\n
are synonymous.
They are not.
\n
means: Add a newline ('\n') to the output.
- endl means: Add a newline to the output,
and flush the output buffer.
- Don’t use endl unless you really want to flush.
It’s not free, and it confuses those who know what it does.
Formatted input
The extraction operator, >>
, is used for input.
You may recognize it as the right shift operator. It’s that, too.
Isn’t operator overloading wonderful?
int i;
cin >> i; // attempt to read an integer
if (cin) // Is the stream in a happy state?
cout << "Read i=" << i << '\n';
-or-
if (!(cin >> i)) // Could we read?
cerr << "Input failed!\n";
Chaining
Input may be chained, just like output:
int a, b, c;
if ((cin>>a) && (cin>>b) && (cin>>c))
cout << "a=" << a << " b=" << b << " c=" << c << '\n';
-or-
int a, b, c;
if (cin >> a >> b >> c)
cout << "a=" << a << " b=" << b << " c=" << c << '\n';
The &&
forces left-to-right evaluation, so the numbers
are read in the proper order.
Read an entire line
Consider this small file:
$ cat ~cs253/pub/ducks
Huey (red)
Dewey (blue)
Louie (green)
To read an entire line, use getline():
const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
for (string line; getline(in, line); )
cout << "► " << line << '\n';
► Huey (red)
► Dewey (blue)
► Louie (green)
Beware
There are two versions of getline():
Read a string
Consider this small file:
$ cat ~cs253/pub/ducks
Huey (red)
Dewey (blue)
Louie (green)
Extracting a string via >>
only reads a whitespace-delimited string.
const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
string s;
while (in >> s)
cout << "► " << s << '\n';
► Huey
► (red)
► Dewey
► (blue)
► Louie
► (green)
Read a character
Consider this small file:
$ cat ~cs253/pub/ducks
Huey (red)
Dewey (blue)
Louie (green)
To read a raw char, without skipping whitespace, use istream::get():
const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
char c;
while (in.get(c))
cout << "►" << c;
►H►u►e►y► ►(►r►e►d►)►
►D►e►w►e►y► ►(►b►l►u►e►)►
►L►o►u►i►e► ►(►g►r►e►e►n►)►
Unlike getline() in the previous slide, istream::get() is a method.
Read a character
Consider this small file:
$ cat ~cs253/pub/ducks
Huey (red)
Dewey (blue)
Louie (green)
Extracting a char via >>
only reads a whitespace-delimited character,
which is rarely useful. That is, it skips whitespace.
const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
char c;
while (in >> c)
cout << "►" << c;
►H►u►e►y►(►r►e►d►)►D►e►w►e►y►(►b►l►u►e►)►L►o►u►i►e►(►g►r►e►e►n►)
Unreading
$ cat ~cs253/pub/ducks
Huey (red)
Dewey (blue)
Louie (green)
To put a character back, use istream::unget():
const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
char c;
in.get(c);
cout << "First character: " << c << '\n';
in.unget(); // no argument
string s;
in >> s;
cout << "First string: " << s << '\n';
First character: H
First string: Huey
Peeking
$ cat ~cs253/pub/ducks
Huey (red)
Dewey (blue)
Louie (green)
To look at the next char without consuming it, use istream::peek():
const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
char c = in.peek();
cout << "First character: " << c << '\n';
string s;
in >> s;
cout << "First string: " << s << '\n';
First character: H
First string: Huey
Stream state
- A stream is put into an error state if something, such as reading
a number, goes wrong, including EOF (end-of-file).
- Test the state by evaluating the stream as an boolean value:
happy=true, error=false.
- To tell the difference between bad input and end-of-file,
use istream::eof().
Don’t do this:
% # This file is only one line.
% cat /etc/hostname
beethoven
% wc -l /etc/hostname
1 /etc/hostname
ifstream in("/etc/hostname");
while (!in.eof()) { // BAD! 😖🙀
string s;
getline(in, s);
cout << "► " << s << '\n';
}
► beethoven
►
- istream::eof() doesn’t ask “Will the next read hit end-of-file?”
- Instead, istream::eof() asks “Did we already hit end-of-file?”
- That is, it doesn’t predict what the next read will do.
- It tells you what the previous read did.
The better way to do it
% cat /etc/hostname
beethoven
ifstream in("/etc/hostname");
string s;
while (getline(in, s))
cout << "► " << s << '\n';
► beethoven
Don’t try to predict the future. Just ask for a line,
and stop when the answer is “no”.
Same for numbers
% cat /proc/uptime
1755102.26 20761612.30
ifstream in("/proc/uptime");
double d;
while (in >> d)
cout << "► " << d << '\n';
► 1.7551e+06
► 2.07616e+07
Now with error checking!
% cat /proc/uptime
1755102.27 20761612.37
ifstream in("/proc/uptime");
double d;
while (in >> d)
cout << "► " << d << '\n';
// Did we stop due to EOF, or bad data?
if (!in.eof())
cerr << "😠\n";
► 1.7551e+06
► 2.07616e+07
Now with error checking!
% cat /proc/uptime
1755102.28 20761612.43
ifstream in("/proc/uptime");
if (!in) { // Is the stream in a bad state?
cerr << "Can’t open /proc/uptime\n";
return 1;
}
int n; // OOPS——should be double
while (in >> n)
cout << "► " << n << '\n';
// Did we stop due to EOF, or bad data?
if (!in.eof())
cerr << "File not full of ints. 😠\n";
► 1755102
File not full of ints. 😠