Input and Output with Streams

C++ reads and writes through streams: std::cout for output, std::cin for input and std::cerr for errors. Streams are type-safe — the compiler picks the right conversion for each value — and manipulators control how numbers are formatted.

Reading with std::cin

The extraction operator >> reads a value into a variable, skipping any spaces and newlines first:

C++
#include <iostream>

int main() {
    int age{};
    std::cout << "How old are you? ";
    std::cin >> age;
    std::cout << "\nNext year you'll be " << age + 1 << ".\n";
}
Input
29
Output
How old are you?
Next year you'll be 30.

The input is shown separately; when you type at a terminal, it appears on the same line as the prompt.

C++
#include <iostream>
#include <string>

int main() {
    std::string item;
    int quantity{};
    double price{};
    std::cin >> item >> quantity >> price;
    std::cout << quantity << " x " << item << " = " << quantity * price << '\n';
}
Input
apples 6 0.45
Output
6 x apples = 2.7

>> into a std::string reads one word — it stops at whitespace.

Reading whole lines

std::getline reads everything up to the end of the line:

C++
#include <iostream>
#include <string>

int main() {
    std::string name;
    std::cout << "Full name: ";
    std::getline(std::cin, name);
    std::cout << "\nHello, " << name << "! (" << name.size() << " characters)\n";
}
Input
Ada Lovelace
Output
Full name:
Hello, Ada Lovelace! (12 characters)

A classic trap: after std::cin >> n, the newline is still waiting in the input, so a following getline returns an empty line. Either skip it with std::cin >> std::ws before getline, or read everything with getline and convert (lesson 9).

Checking for bad input

If the input can't be converted — letters where a number was expected — the stream enters a fail state, the variable gets 0, and further reads do nothing until you clear it. Test the stream like a boolean:

C++
#include <iostream>
#include <limits>

int main() {
    int guests{};
    while (true) {
        std::cout << "How many guests? ";
        if (std::cin >> guests && guests > 0) break;
        if (std::cin.eof()) return 1;                    // input ended
        std::cout << "\nPlease enter a positive whole number.\n";
        std::cin.clear();                                // reset the fail state
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // discard the bad line
    }
    std::cout << "\nSetting " << guests << " places.\n";
}
Input
lots
-3
6
Output
How many guests?
Please enter a positive whole number.
How many guests?
Please enter a positive whole number.
How many guests?
Setting 6 places.

Reading until input ends

Because a stream converts to false once input runs out, a read can be a loop condition. This processes every number until the end of input (or a file redirected with ./main < data.txt):

C++
#include <iostream>

int main() {
    double value{}, total{};
    int count{};
    while (std::cin >> value) {
        total += value;
        ++count;
    }
    std::cout << count << " values, average " << total / count << '\n';
}
Input
12.5 7.25
30 18
Output
4 values, average 16.9375

Formatting output

Manipulators from <iomanip> change how the next values are printed:

C++
#include <iomanip>
#include <iostream>

int main() {
    double pi = 3.14159265;
    std::cout << pi << '\n';                                       // default: 6 significant digits
    std::cout << std::fixed << std::setprecision(2) << pi << '\n'; // 2 decimal places
    std::cout << std::setw(8) << 42 << "|\n";                      // width 8, right-aligned
    std::cout << std::left << std::setw(8) << 42 << "|\n";         // left-aligned
    std::cout << std::setfill('0') << std::right << std::setw(5) << 42 << '\n';
    std::cout << std::hex << 255 << ' ' << std::dec << 255 << '\n';
    std::cout << std::boolalpha << true << '\n';
}
Output
3.14159
3.14
      42|
42      |
00042
ff 255
true

Most manipulators are sticky — they stay in effect until changed — except setw, which applies only to the next value. That stickiness is one reason many programmers prefer std::format (lesson 45) for anything non-trivial.

A formatted table

C++
#include <iomanip>
#include <iostream>
#include <string>

int main() {
    std::cout << std::left << std::setw(10) << "Item" << std::right << std::setw(5) << "Qty"
              << std::setw(9) << "Price" << '\n';
    std::cout << std::fixed << std::setprecision(2);
    std::cout << std::left << std::setw(10) << "Notebook" << std::right << std::setw(5) << 4 << std::setw(9) << 3.5 << '\n';
    std::cout << std::left << std::setw(10) << "Pen" << std::right << std::setw(5) << 10 << std::setw(9) << 1.2 << '\n';
}
Output
Item        Qty    Price
Notebook      4     3.50
Pen          10     1.20

Errors go to std::cerr

std::cerr writes to standard error, which stays visible when normal output is redirected to a file, and is unbuffered so messages appear immediately:

C++
std::cerr << "Error: could not open " << filename << '\n';

Try it yourself

Read a list of temperatures until input ends and print the lowest, highest and average with one decimal place.

Try it yourself · main.cpp
Edit the code, copy it into main.cpp, then compile and run it with c++ -std=c++20 -Wall main.cpp -o main && ./main. How to set up a C++ compiler
Input
14.5 17 12.25 19.75 16
Output
min 12.2, max 19.8, mean 15.9