C++ Input & Output: Master cin, cout, Formatting & File I/O Basics
What Are Streams in C++?
In C++, input and output are handled through streams — abstract sequences of bytes that flow between your program and the outside world. Think of a stream as a pipe: data goes in one end and comes out the other. The <iostream> header gives you four predefined streams:
std::cout— Standard output (your terminal). The<<operator sends data to it.std::cin— Standard input (your keyboard). The>>operator reads data from it.std::cerr— Standard error (unbuffered, for error messages).std::clog— Standard log (buffered, for log messages).
The stream model is one of C++’s most powerful abstractions because the same << and >> operators work with files, strings, and network sockets — not just the terminal. You learn the operators once and use them everywhere.
Output with std::cout
#include <iostream>
#include <string>
int main() {
// Basic output
std::cout << "Hello, World!" << std::endl;
// Chaining multiple values
std::string name = "Chirag";
int age = 25;
double gpa = 3.85;
std::cout << "Name: " << name << ", Age: " << age << ", GPA: " << gpa << "\n";
// endl vs \n
// std::endl flushes the buffer (slower)
// "\n" just adds a newline (faster)
// Use "\n" in most cases. Use endl only when you need guaranteed flush.
std::cout << "Line 1\n";
std::cout << "Line 2\n";
std::cout << "Line 3" << std::endl; // Flush here
// Printing special characters
std::cout << "Tab:\there\n";
std::cout << "Quote: \"hello\"\n";
std::cout << "Backslash: \\\n";
std::cout << "Newline in string: first\nsecond\n";
return 0;
}
The << operator is called the insertion operator. It is overloaded for all fundamental types — int, double, char, const char*, std::string, and more. You will learn how to overload it for your own types in the operator overloading lesson.
Input with std::cin
#include <iostream>
#include <string>
int main() {
// Reading a single value
int age;
std::cout << "Enter your age: ";
std::cin >> age;
std::cout << "You are " << age << " years old.\n";
// Reading multiple values on one line
double width, height;
std::cout << "Enter width and height: ";
std::cin >> width >> height;
std::cout << "Area: " << width * height << "\n";
// Reading a single word (cin stops at whitespace)
std::string word;
std::cout << "Enter a word: ";
std::cin >> word;
std::cout << "You entered: " << word << "\n";
// If you type "Hello World", only "Hello" is read!
return 0;
}
The >> operator is called the extraction operator. It reads from the input stream, skipping leading whitespace, and stops at the next whitespace character. This means std::cin >> word reads one word, not a full line.
Reading Full Lines with std::getline
#include <iostream>
#include <string>
int main() {
std::string fullName;
std::string city;
std::cout << "Enter your full name: ";
std::getline(std::cin, fullName);
std::cout << "Enter your city: ";
std::getline(std::cin, city);
std::cout << "Hello, " << fullName << " from " << city << "!\n";
return 0;
}
// Sample run:
// Enter your full name: Chirag Khatri
// Enter your city: San Francisco
// Hello, Chirag Khatri from San Francisco!
std::getline(std::cin, variable) reads the entire line including spaces, up to the newline character. It discards the newline but does not skip leading whitespace like >> does.
The cin/getline Trap
This is the most common beginner bug in C++ I/O. When you mix cin >> and getline, the leftover newline from cin >> causes getline to read an empty string:
#include <iostream>
#include <string>
int main() {
int age;
std::string name;
// BUG VERSION
std::cout << "Enter age: ";
std::cin >> age; // Reads "25" but leaves "\n" in the buffer
std::cout << "Enter name: ";
std::getline(std::cin, name); // Reads the leftover "\n" immediately!
// name is now empty!
std::cout << "Age: " << age << ", Name: '" << name << "'\n";
// Output: Age: 25, Name: ''
return 0;
}
#include <iostream>
#include <string>
#include <limits>
int main() {
int age;
std::string name;
// FIX 1: Use cin.ignore() to discard the leftover newline
std::cout << "Enter age: ";
std::cin >> age;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "Enter name: ";
std::getline(std::cin, name);
std::cout << "Age: " << age << ", Name: '" << name << "'\n";
// Now works correctly!
return 0;
}
// FIX 2: Use getline for everything and convert
// std::string ageStr;
// std::getline(std::cin, ageStr);
// int age = std::stoi(ageStr);
This trap catches every beginner. Memorize the fix: after every cin >> that precedes a getline, call cin.ignore().
Error Output — cerr and clog
#include <iostream>
#include <fstream>
int main() {
// cerr — for error messages (unbuffered, writes immediately)
std::cerr << "Error: file not found!\n";
// clog — for log messages (buffered, more efficient)
std::clog << "Log: application started\n";
// Why separate streams? You can redirect them independently:
// ./program > output.txt 2> errors.txt
// stdout goes to output.txt, stderr goes to errors.txt
std::cout << "This goes to stdout\n";
std::cerr << "This goes to stderr\n";
return 0;
}
Formatting Output — Manipulators
#include <iostream>
#include <iomanip> // Required for most manipulators
int main() {
double pi = 3.14159265358979;
// Precision control
std::cout << "Default: " << pi << "\n"; // 3.14159
std::cout << std::setprecision(3) << pi << "\n"; // 3.14
std::cout << std::fixed << std::setprecision(2) << pi << "\n"; // 3.14
std::cout << std::scientific << pi << "\n"; // 3.14e+00
// Reset to default
std::cout << std::defaultfloat;
// Width and alignment
std::cout << std::setw(10) << "Name" << std::setw(10) << "Score" << "\n";
std::cout << std::setw(10) << "Alice" << std::setw(10) << 95 << "\n";
std::cout << std::setw(10) << "Bob" << std::setw(10) << 87 << "\n";
// Fill character
std::cout << std::setfill('-') << std::setw(30) << "" << "\n"; // prints 30 dashes
std::cout << std::setfill('0') << std::setw(5) << 42 << "\n"; // 00042
std::cout << std::setfill(' '); // Reset fill
// Number bases
int num = 255;
std::cout << "Decimal: " << std::dec << num << "\n"; // 255
std::cout << "Hex: " << std::hex << num << "\n"; // ff
std::cout << "Octal: " << std::oct << num << "\n"; // 377
std::cout << std::dec; // Reset to decimal
// Show base prefix
std::cout << std::showbase;
std::cout << "Hex: " << std::hex << num << "\n"; // 0xff
std::cout << std::dec << std::noshowbase;
// Boolean output
bool flag = true;
std::cout << "bool: " << flag << "\n"; // 1
std::cout << "bool: " << std::boolalpha << flag << "\n"; // true
return 0;
}
printf-Style Output in C++
#include <cstdio> // C-style printf
#include <iostream>
// C++20 introduced std::format (header <format>)
// C++23 introduced std::print (header <print>)
int main() {
// Classic printf — still works in C++ and is sometimes more readable
printf("Name: %s, Age: %d, GPA: %.2f\n", "Chirag", 25, 3.85);
printf("Hex: 0x%X, Octal: %o\n", 255, 255);
printf("Padded: %010d\n", 42); // 0000000042
// C++20 std::format (if your compiler supports it)
// #include <format>
// std::string s = std::format("Name: {}, Age: {}, GPA: {:.2f}", "Chirag", 25, 3.85);
// std::cout << s << "\n";
// C++23 std::print (if your compiler supports it)
// #include <print>
// std::print("Name: {}, Age: {}\n", "Chirag", 25);
return 0;
}
Use cout with manipulators for type-safe output. Use printf when format strings are more readable (tables, aligned columns). In C++23, std::print gives you the best of both worlds.
String Streams — std::stringstream
#include <iostream>
#include <sstream>
#include <string>
int main() {
// Building strings with stringstream
std::ostringstream oss;
oss << "Score: " << 95 << "/100 (" << 95.0 << "%)";
std::string result = oss.str();
std::cout << result << "\n";
// Parsing strings with istringstream
std::string data = "42 3.14 Hello";
std::istringstream iss(data);
int num;
double pi;
std::string word;
iss >> num >> pi >> word;
std::cout << "Parsed: " << num << ", " << pi << ", " << word << "\n";
// Converting string to number
std::string numStr = "12345";
int value = std::stoi(numStr); // string to int
double dval = std::stod("3.14"); // string to double
std::cout << value << " " << dval << "\n";
// Converting number to string
std::string s = std::to_string(42);
std::cout << "As string: " << s << "\n";
return 0;
}
Input Validation and Error Handling
#include <iostream>
#include <limits>
int main() {
int number;
while (true) {
std::cout << "Enter a positive integer: ";
if (std::cin >> number) {
if (number > 0) {
break; // Valid input
}
std::cout << "Must be positive!\n";
} else {
// Input was not a valid integer
std::cout << "Invalid input! Please enter a number.\n";
std::cin.clear(); // Clear the error flag
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); // Discard bad input
}
}
std::cout << "You entered: " << number << "\n";
return 0;
}
// Sample run:
// Enter a positive integer: abc
// Invalid input! Please enter a number.
// Enter a positive integer: -5
// Must be positive!
// Enter a positive integer: 42
// You entered: 42
When cin >> fails (e.g., you type letters when it expects a number), the stream enters a fail state. You must call cin.clear() to reset the error flag and cin.ignore() to discard the bad input before trying again.
Reading Multiple Values
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
int main() {
// Reading comma-separated values
std::string line;
std::cout << "Enter numbers separated by commas: ";
std::getline(std::cin, line);
std::vector<int> numbers;
std::istringstream iss(line);
std::string token;
while (std::getline(iss, token, ',')) {
numbers.push_back(std::stoi(token));
}
std::cout << "You entered " << numbers.size() << " numbers: ";
for (int n : numbers) {
std::cout << n << " ";
}
std::cout << "\n";
// Reading until EOF (useful for competitive programming)
// int x;
// while (std::cin >> x) {
// // Process x
// }
return 0;
}
// Sample run:
// Enter numbers separated by commas: 10,20,30,40
// You entered 4 numbers: 10 20 30 40
Practice Exercises
// Exercise 1: Create a receipt formatter
// Input: item name, quantity, price per item
// Output: formatted receipt with total, aligned columns
// Exercise 2: Build a number base converter
// Input: a decimal number
// Output: same number in binary, octal, and hexadecimal
// Exercise 3: Create a simple calculator
// Input: two numbers and an operator (+, -, *, /)
// Output: the result, formatted to 2 decimal places
// Handle division by zero!
// Exercise 4: Read a full paragraph (multiple lines) until the user types "END"
// Print the total word count and character count
// Exercise 5: Build a "Mad Libs" game
// Ask for: a noun, a verb, an adjective, a place
// Print a silly story using those words
Summary
C++ I/O is built on the stream abstraction. std::cout and << handle output. std::cin and >> handle input. std::getline reads full lines. Manipulators from <iomanip> control formatting — precision, width, fill, alignment, and number bases. std::stringstream lets you build and parse strings using the same stream operators. Always validate user input and watch out for the cin >> / getline trap.
In the next lesson, we cover operators and expressions — arithmetic, comparison, logical, bitwise, and the precedence rules that govern them all.