CS 112
Introduction to Data Structures
Week 02
File I/O, Exceptions, 2D Arrays
Eric Araújo
Calvin University · Fall 2026
throw, try, catch
#include <iostream>
int n;
cin >> n; // in
cout << n; // out
#include <fstream>
ifstream fin("data.txt");
fin >> n; // in
ofstream fout("out.txt");
fout << n; // out
#include <fstream>
// A file that isn't there does NOT crash your program.
// The stream quietly fails, so you have to ask.
ifstream fin("numbers.txt"); // open on construction
if (!fin) { // ALWAYS check
cerr << "cannot open it" << endl;
return 1;
}
ifstream fin2; // or open later
fin2.open("numbers.txt");
if (!fin2.is_open()) { ... } // the same check, spelled out
fin.close(); // done with it
fstreamifstreaminstreamfinifstream. Read it as input file stream. fin is just a variable name people conventionally use; fstream can do both directions.
ifstream fin("file");: what is another?
ifstream fin.open("file");ifstream open("file") as fin;ifstream fin;fin.open("file");ifstream fin().open("file");.open() on it. Useful when the filename isn't known until later.
string word;
fin >> word;
// stops at whitespace
string line;
getline(fin, line);
// stops at newline
// How do you know when a file is finished?
// You try to read, and the read fails. There is no
// "am I at the end?" to ask first. So: read, THEN test.
string line;
while (getline(fin, line)) {
cout << line << endl;
}
numbers.txt holds three lines. getline starts at
the top and moves the position past each line it takes.
▶12 7 30 EOF
12 ▶7 30 EOF
12 7 30 ▶EOF
12 7 30 ▶EOF
The fourth read is the one that tells you the file is
over. It has to be attempted, and it has to fail. That is why the read
goes inside the while and not before it.
string s;
while (true) {
getline(fin, s);
cout << s << endl;
if (!fin) { break; }
}
getline fails and leaves s holding the previous line, but cout runs before the check. Test the read immediately: while (getline(fin, s)).
ofstream fout("results.txt");
assert(fout.is_open()); // or if (!fout), as before
for (int i = 0; i < n; ++i) {
fout << names[i] << "," << scores[i] << "\n";
}
// Forget close() and the last writes may still be
// sitting in the buffer, not on disk. You can lose them.
fout.close();
// Opening for writing TRUNCATES by default: the file
// is empty the moment you open it, whatever was in it.
ofstream fout("log.txt");
// ios::app keeps what is there and writes after it.
ofstream fout("log.txt", ios::app);
started
started started
Same program, same line written. The flag is the only difference, and it decides whether yesterday's run still exists.
\n, endl, flush| You write | Newline? | Flushes? | Use it when |
|---|---|---|---|
<< "\n" | yes | no | almost always |
<< endl | yes | yes | you need it on disk now |
<< flush | no | yes | mid-line prompts, progress dots |
Type this, run it, and in a second terminal watch
buf.txt while it sleeps. Then swap
"\n" for endl and run it again.
#include <fstream>
#include <unistd.h> // sleep()
using namespace std;
int main() {
ofstream fout("buf.txt");
fout << "hello" << "\n"; // then try: << endl
sleep(10); // ls -l buf.txt in another terminal
fout.close();
}
| Program prints | File after 1 second | After the program exits |
|---|---|---|
"hello" << "\n" | 0 bytes, nothing yet | 6 bytes |
"hello" << endl | 6 bytes, hello\n | 6 bytes |
"hello" << flush | 5 bytes, hello (no newline) | 5 bytes |
Reading a file that isn't there.
(the file was right there. in the other folder.)
average(int a[], int n) is called with n = 0. There is no average of nothing. What can your function do?
-1 or 0| What it does | Why it hurts | |
|---|---|---|
| A | print an error | a function that computes averages should not decide how this program talks to its user. In a GUI there is no console to print to |
| B | return -1 |
-1 is a perfectly good average. The caller cannot tell
your failure from a real answer |
| C | carry on | the caller never learns anything went wrong, and the bad value spreads into everything computed from it |
| D | throw |
the function reports what it cannot do; the caller decides what that means. Nobody can ignore it by accident |
throw and catch
#include <stdexcept> // invalid_argument lives here
// ...
double squareRoot(double x) {
if (x < 0) {
throw invalid_argument("negative input");
}
return sqrt(x);
}
// ...
try {
cout << squareRoot(value);
} // & : catch by REFERENCE. Catching by
catch (invalid_argument &e) { // value copies the exception, and
cerr << "cannot do that: " // slices off anything a derived
<< e.what() << endl; // type added
}
void c() {
cout << "in c" << endl;
throw runtime_error("boom");
cout << "after throw"; // never runs
}
void b() {
cout << "in b" << endl;
c();
cout << "back in b"; // never runs
}
int main() {
try {
b();
cout << "after b"; // never runs
} catch (runtime_error &e) {
cout << "caught: " << e.what();
}
cout << " done" << endl;
}
| Stack | What happens |
|---|---|
main | enters the try, calls b |
main → b | prints in b, calls c |
main → b → c | prints in c, then throws |
main → b | c abandoned. No handler in b, so b is abandoned too |
main | the try has a handler: catch runs |
Output:
in b · in c ·
caught: boom done
Three lines marked never runs. The throw does not return anywhere; it leaves every frame between itself and the handler, and each abandoned frame destroys its locals on the way out.
void f() { throw invalid_argument("yuck");
cout << "a"; }
void g() { cout << "b"; f(); cout << "c"; }
int main() { cout << "d"; g(); f(); cout << "e"; }
db and then crashes. Nothing catches the exception, so it propagates out of g(), out of main(), and the runtime calls terminate(). Neither c nor e is ever reached.
const unsigned ROWS = 5;
const unsigned COLS = 8;
char board[ROWS][COLS]; // 5 rows, 8 columns
for (unsigned r = 0; r < ROWS; ++r) {
for (unsigned c = 0; c < COLS; ++c) {
board[r][c] = '.';
}
}
board[r][c]. The outer loop walks rows, the inner walks the cells within a row.int grid[2][4] is not a grid; it is 8 ints in a row.
const unsigned COLS = 8;
void printBoard(char b[][COLS], unsigned rows) {
...
}
b[r][c] can't be turned into an addresscin/coutis_open(): a missing file fails silentlywhile (getline(fin, line))throw hands the problem to whoever can decide what to do
This deck stands on earlier CS112 materials by
Joel Adams and Victor Norman · adapted and extended by Eric Araújo