Streams and I/O

Streams are the fundamental mechanism for text-based I/O (input/output) in C++, whether it's printing messages and taking input from the user via the terminal, reading and writing to files, or a number of other applications.

Programs can also receive input via command-line arguments provided when it is initally run.

We'll cover these as well as a number of miscellaneous topics related to programs and the command-line environment from which they run, including exit codes, input/output redirection, and pipelining.

Updated Fall 2024

1: Standard Input and Output
1.1 Not Started

The familiar cin and cout variables in C++ are the realization of standard input and output streams that allow a program to communicate with its runtime environment. By default, this might be communication with a user typing at the terminal, but these streams can also be redirected to/from files or connected to other programs as part of a pipeline.

Here's the details and several examples:


1.1

Consider this command run at the terminal. Assume filter.exe and meow.exe are C++ programs.

  ./filter.exe < cats.txt | ./meow.exe

Which of the following are true?



2: File Streams

Streams are also used for reading and writing files in C++. First, some basics:


In the previous video, we saw that the program should return 1; if it runs into an error opening the file. This is an "exit code" or "exit status" that indicates something has gone wrong to the parent process that originally invoked the program. Now seems like a reasonable time to take a detour to talk a bit more about exit codes generally…




3: Patterns for File Input in C++

File input can be fairly complex, but there are a few common patterns that tend to work well. These depend on a some specifics of the stream operators and interface in C++, so we'll introduce those first.


Now, on to some common patterns (and anti-patterns!) for file input in C++…




4: Stream Functions and Unit Testing with Stringstreams

This section addresses a few design considerations for functions that performs input/output.

First, it's generally best to pass generic ostream or istream objects to the function, so that it can potentially be used with any different kind of stream (e.g. sometimes write output to cout and other times to a file through an ofstream).

Additionally, how can you write automated unit tests for the function? (You can't just have someone sit there and type input via cin every time you want to run tests.) Instead, use stringstreams - special stream objects that can essentially "fake" input/output operations.

The video below covers both in more detail.




5: Command Line Arguments

One last place we might like to take in input - when the program is originally launched from the terminal. For example, in project 2, the image resizing program takes arguments that look something like this:

./resize.exe horses.ppm horses_400x250.ppm 400 250

Let's take a look at how this works in C++:




6: Exercise: Word Count
6.1 Not Started

In this exercise, implement a program that counts the number of words in a set of files, which are specified by providing their filenames as command line arguments.

If a particular file does not open successfully, the program should print "Skipping file: " with the associated filename and continue on to the next file.

wordcount.exe Example

Assume these files are present in the current working directory:

File Name Contents
greeting.txt hello world!
fav_class.txt EECS 280 is awesome :)
fav_colors.txt red blue green

If the program was compiled to wordcount.exe and run as:

./wordcount.exe greeting.txt aaaaa.txt fav_class.txt

The output to cout would be:

greeting.txt has 2 words.
Skipping file: aaaaa.txt
fav_class.txt has 5 words.
7 words in total.

(Note that fav_colors.txt was not specified and therefore ignored.)

6.1

Implement the program by filling in the boxes below.

#include <string>
#include <iostream>
#include <fstream>

using namespace std;

// MODIFIES: The given input stream
// EFFECTS:  Reads all input from the given input stream and returns the
//           number of words in the input (with words separated from each
//           other by whitespace).
int word_count( input) {

  string word;
  int count = 0;
  while() {
    ++count;
  }
  return count;
}

int main(int argc, char *argv[]) {
  int total = 0;
  for(int i = ; ; ++i) {
    string filename = ;
    ifstream fin();

    if () {
      cout << "Skipping file: " << filename << endl;
      continue;
    }
    int wc = ;
    cout << filename << " has " << wc << " words." << endl;
    total += wc;

    fin.close(); // technically not needed since fin is going out of scope each iteration
  }

  cout << total << " words in total." << endl;
}
You've reached the end of this lecture! Your work on any exercises will be saved if you re-open this page in the same web browser.

Participation Credit
Make sure to sign in to the page, complete each of the exercises, and double check the participation indicator at the top left of this page to ensure you've earned credit.