CS253: Software Development with C++

Fall 2021

Input/Output

Show Lecture.IO as a slide show.

CS253 I/O

I/O Class Hierarchy

I/O Class Hierarchy

or, if you prefer a diagram:

                                    ┌─────┐
                                    │ ios │
                                    └─────┘
                                       △
                      ┌────────────────┴────────────────┐
                 ┌────┴────┐                       ┌────┴────┐
                 │ istream │                       │ ostream │
                 └─────────┘                       └─────────┘
                      △                                 △
               ┌──────┴───────┐                  ┌──────┴───────┐
         ┌─────┴────┐ ┌───────┴───────┐  ┌───────┴───────┐ ┌────┴─────┐
         │ ifstream │ │ istringstream │  │ ostringstream │ │ ofstream │
         └──────────┘ └───────────────┘  └───────────────┘ └──────────┘

The △ indicates inheritance.

More

                           ┌─────┐
                           │ ios │
                           └─────┘
                              △
             ┌────────────────┴────────────────┐
        ┌────┴────┐                       ┌────┴────┐
        │ istream │                       │ ostream │
        └─────────┘                       └─────────┘
             △                                 △
      ┌──────┴───────┐                  ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐  ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │  │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘  └───────────────┘ └──────────┘

Methods & Operator Overloading

                           ┌─────┐
                           │ ios │
                           └─────┘
                              △
             ┌────────────────┴────────────────┐
        ┌────┴────┐                       ┌────┴────┐
        │ istream │                       │ ostream │
        └─────────┘                       └─────────┘
             △                                 △
      ┌──────┴───────┐                  ┌──────┴───────┐
┌─────┴────┐ ┌───────┴───────┐  ┌───────┴───────┐ ┌────┴─────┐
│ ifstream │ │ istringstream │  │ ostringstream │ │ ofstream │
└──────────┘ └───────────────┘  └───────────────┘ └──────────┘

What Header Files Define What

<sstream> <fstream> <iostream> <iomanip>
objects manipulators

istringstream ostringstream stringstream

ifstream ofstream fstream

cin cout cerr clog

These don’t take an argument:

boolalpha noboolalpha showbase noshowbase showpoint noshowpoint showpos noshowpos skipws noskipws uppercase nouppercase left right internal dec hex oct fixed scientific

These do take an argument

resetiosflags setiosflags setbase setfill setprecision setw (non-sticky)

strange type?

Consider the error message from this bad code:

cout.zork();
c.cc:1: error: 'std::ostream' {aka 'class std::basic_ostream<char>'} has no 
   member named 'zork'

basic_ostream

Why!?

w-streams

wchar_t

char c = 'X';
wchar_t wc = L'⻥';
cout << sizeof(c) << '\n'
     << sizeof(wc) << '\n';
1
4

basic_whatever<type>

Unformatted output

We’re familiar with formatted I/O using << or >>:

cout << "π ≈ " << 355/113.0 << endl;
π ≈ 3.14159

There’s also unformatted output:

cout.put('h');
cout.put('i');
char data[] = " there\nextra";
cout.write(data, 7);
hi there

Unformatted input

With unformatted input, you can read an arbitrary number of bytes:

ifstream in("/etc/resolv.conf");
char buf[80];
in.read(buf, size(buf));
cout << "⊢";
cout.write(buf, in.gcount());
cout << "⊣";
⊢search cs.colostate edu colostate.edu
nameserver 129.82.45.181
nameserver 129.82⊣

istream::read() reads into a char buffer, which is not '\0' terminated.

char-based unformatted input

ifstream in("/etc/resolv.conf");
char c;
c = in.peek(); cout << "First: " << c << "\n";
c = in.get(); cout << "Again: " << c << "\n";
in.unget();
c = in.get(); cout << "Again: " << c << "\n";
c = in.get(); cout << "Second: " << c << "\n";
in.ignore(10000, '9');
while (in.get(c)) cout.put(c);
First: s
Again: s
Again: s
Second: e
.82.45.181
nameserver 129.82.103.78
nameserver 129.82.103.79

seek/tell


Diogenes

Only one

Surprisingly (well, it surprised me), an fstream (ifstream/ofstream combination) has only a single shared put/get pointer, and not one for input and one for output.

seek/tell methods


Misuse of .open()

ifstream and ofstream both inherited fstream::open():

const string home = getpwnam("cs253")->pw_dir;
ifstream in;
in.open(home+"/pub/ducks");
for (char c; in.get(c); )
    cout << c;
Huey (red)
Dewey (blue)
Louie (green)

Why have that extra step? Just associate the filename at object construction:

const string home = getpwnam("cs253")->pw_dir;
ifstream in(home+"/pub/ducks");
for (char c; in.get(c); )
    cout << c;
Huey (red)
Dewey (blue)
Louie (green)

Misuse of .eof()

ifstream in("/etc/hostname");
string line;
while (!in.eof()) {  // BAD!
    getline(in, line);
    cout << "Data: " << line << '\n';
}
Data: beethoven
Data: 

Where did that extra line come from?

The right way to detect end-of-file

Don’t inquire in advance—just go ahead and read. It will succeed or fail:

ifstream in("/etc/hostname");
string line;
while (getline(in, line))
    cout << line << '\n';
beethoven

Or, with fewer source lines and a reduced scope for line:

ifstream in("/etc/hostname");
for (string line; getline(in, line); )
    cout << line << '\n';
beethoven