Skip to Content

C++: I/O Streams

Plain C has library-function based I/O capabilities, centered around the printf/scanf family of functions (and others).

C++ introduced a new OO-designed I/O package called iostreams, and embodied in the header . Some people love it, and some people hate it, but it is here to stay.

To use iostreams, you have to do

#include <iostream>

You will probably also include other headers, like string and others.

Iostreams give you three standard channels, the standard input, called std::cin, the standard output, called std::cout, and the standard error output, called std::cerr.

Many people will do using namespace std; after the include line above, and then directly use the symbols cin, cout, and cerr without the std:: qualification. This is bad practice, because the namespace std has many many symbols that get imported in the using statement, and some may conflict with your own names. I strongly recommend just using std::cout, etc., rather than importing. If you really want to use the short versions, then do using std::cout; and only import that single symbol (and then do the same for cin and cerr if you need to.

Output

Output is done using the << operator, with std::cout or std::cerr (or other file stream handle) on the left, and then multiple right-hand arguments, each separated by <<.

The constant named std::endl represents a newline character. You can use it to end the current output line and start a new line, but newer practice actually prefers just using a \n character in a string.

The two lines below do the same thing:

std::cout << "my int var is " << i << " and my double var is " << d << std::endl;
std::cout << "my int var is " << i << " and my double var is " << d << "\n";

Input

Input is done using the >> operator with std::cin on the left (or other input file stream handle), and multiple variables on the right. For example,

std::cin >> i >> d;

will input an integer value and then a double value, and assign them to the variables i and d, respectively.

Although it looks wierd, it is actually safer than the printf/scanf form, because the compiler can check and verify that the values being assigned to the variables are of the same type. A plain C compiler cannot do the same types of checks with printf/scanf.

String-based Input

Input streams is a generic feature and not just useful for std::cin; indeed, most of our data comes from files and other sources. If you have some user input in the form of a single std:string, and you need to extract data from it, you can create a “string stream” object that will let you use the >> operator to extract data pieces.

The first line below declares and constructs an object named lineStream from a string named line. The lineStream can then be used as an input stream, as shown below on the third line.

    std::istringstream lineStream(line);
    ...
    lineStream >> myIntVar;  // example

Line-Oriented File Input

While input stream input can be great in many places, many data files, especially human-readable data formats like Comma-Separated-Values, are line oriented, meaning that each line is some individual record of data. The input stream >> operator generally ignores newlines, and so if it gets off due to a bad input file, the rest of the data will be read incorrectly!

It is much safer to process line-oriented data files in a line-oriented fashion. The code below is an example of doing this, using the std::getline() function rather than the >> operator. Each line is then a std::string object, and we use the string stream capability to parse the data out of it (oddly enough, the std::getline() function is still a good way to do this, but you could use the >> operator if your data format was suitable).

#include <iostream>
#include <fstream>
#include <sstream>

int main(int argc, char* argv[])
{
    if (argc != 2) {
        std::cerr << "Error: a filename argument must be given\n";
        return -1;
    }
    // create an input stream object for the filename given as an argument;
    // this also opens the file for reading
    std::ifstream inFile(argv[1]);
    std::string line;
    if (!inFile) {
        std::cerr << "Error: file " << argv[1] << " cannot be opened\n";
        return -1;
    }
    // read the file line by line; this is safer than trying to 
    // parse the lines as you read the data in
    while (std::getline(inFile, line)) {
        std::cout << "line is [" << line << "]\n";
        if (line.length() < 2)
            continue; // probably at end of file
        std::istringstream lineStream(line);
        std::string piece;
        // loop below separates pieces of the line by commas
        while (std::getline(lineStream, piece, ',')) {
            // remove quotes if they are part of the piece string
            if (piece.front() == '"' && piece.back() == '"')
                piece = piece.substr(1,piece.size()-2);
            std::cout << "  piece [" << piece << "]\n";
        }
    }
    inFile.close();
    std::cout << "Done processing the file.\n";
    return 0;
}