Show Lecture.IOStreams as a slide show.
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.
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?
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.
cout << "alpha\n"; cout << "beta" << endl; cout << "gamma" << "\n"; cout << "delta" << '\n';
alpha beta gamma delta
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.
endl
unless you really want to flush.
It’s not free, and it confuses those who know what it does.
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";
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.
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"); string line; while (getline(in, line)) cout << "► " << line << '\n';
► Huey (red) ► Dewey (blue) ► Louie (green)
There are two versions of getline
:
std::string
.
istream
that deals with C-style strings.
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)
Consider this small file:
$ cat ~cs253/pub/ducks Huey (red) Dewey (blue) Louie (green)
To read a raw char
, without skipping whitespace, use 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, get
is a method.
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►)
$ cat ~cs253/pub/ducks Huey (red) Dewey (blue) Louie (green)
To put a character back, use .unget()
:
const string home = getpwnam("cs253")->pw_dir; ifstream in(home+"/pub/ducks"); char c; in >> 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
cin.eof()
% # 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 ►
.eof()
doesn’t ask “Will the next read hit end-of-file?”
.eof()
asks “Did we already hit end-of-file?”
% 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”.
% cat /proc/uptime 5628750.19 66506301.60
ifstream in("/proc/uptime"); double d; while (in >> d) cout << "► " << d << '\n';
► 5.62875e+06 ► 6.65063e+07
% cat /proc/uptime 5628750.21 66506301.68
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";
► 5.62875e+06 ► 6.65063e+07
% cat /proc/uptime 5628750.22 66506301.76
ifstream in("/proc/uptime"); 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 << "😠\n";
► 5628750 😠