Coming Soon
This lesson is currently being developed
Input and output (I/O) streams
Learn about Input and output (I/O) streams in C++.
What to Expect
Comprehensive explanations with practical examples
Interactive coding exercises to practice concepts
Knowledge quiz to test your understanding
Step-by-step guidance for beginners
Development Status
Content is being carefully crafted to provide the best learning experience
Preview
Early Preview Content
This content is still being developed and may change before publication.
28.1 — Input and output (I/O) streams
In this lesson, you'll learn about C++'s stream-based input/output system, which provides a unified way to handle data from various sources like the console, files, and strings.
What are I/O streams?
An I/O stream is an abstraction that represents a sequence of data that can be read from or written to. Think of streams like water pipes - data flows through them in one direction, and you can attach different sources (keyboard, file) or destinations (screen, file) to these pipes.
C++ uses streams for all input/output operations, making I/O consistent whether you're working with:
- Console (keyboard/screen)
- Files
- Strings in memory
- Network connections
The stream hierarchy
C++ provides several stream classes in the <iostream>
header:
#include <iostream>
// This gives us access to:
// - std::cin (input from console)
// - std::cout (output to console)
// - std::cerr (error output to console)
// - std::clog (logging output to console)
Key stream types
- Input streams (
std::istream
): Read data - Output streams (
std::ostream
): Write data - Input/output streams (
std::iostream
): Both read and write
Basic stream operations
Output with std::cout
You've already used std::cout
many times:
#include <iostream>
int main()
{
std::cout << "Hello, World!" << std::endl;
int age = 25;
std::cout << "I am " << age << " years old." << std::endl;
// Chaining multiple outputs
std::cout << "Values: " << 10 << ", " << 3.14 << ", " << 'A' << std::endl;
return 0;
}
Output:
Hello, World!
I am 25 years old.
Values: 10, 3.14, A
Input with std::cin
Reading data from the console:
#include <iostream>
#include <string>
int main()
{
std::string name;
int age;
std::cout << "Enter your name: ";
std::cin >> name;
std::cout << "Enter your age: ";
std::cin >> age;
std::cout << "Hello " << name << ", you are " << age << " years old." << std::endl;
return 0;
}
Sample run:
Enter your name: Alice
Enter your age: 30
Hello Alice, you are 30 years old.
Understanding stream operators
Insertion operator (<<
)
The <<
operator "inserts" data into an output stream:
std::cout << "Data flows into cout" << std::endl;
// ^^
// insertion operator
Extraction operator (>>
)
The >>
operator "extracts" data from an input stream:
int number;
std::cin >> number; // Extract integer from cin into number
// ^^
// extraction operator
Stream manipulation and formatting
Basic formatting with std::cout
#include <iostream>
#include <iomanip> // For stream manipulators
int main()
{
double pi = 3.14159265359;
// Default output
std::cout << "Default: " << pi << std::endl;
// Set precision
std::cout << std::fixed << std::setprecision(2);
std::cout << "2 decimal places: " << pi << std::endl;
std::cout << std::setprecision(4);
std::cout << "4 decimal places: " << pi << std::endl;
// Set width and alignment
std::cout << std::setw(10) << "Right" << std::endl;
std::cout << std::left << std::setw(10) << "Left" << std::endl;
return 0;
}
Output:
Default: 3.14159
2 decimal places: 3.14
4 decimal places: 3.1416
Right
Left
Number base formatting
#include <iostream>
int main()
{
int number = 255;
std::cout << "Decimal: " << std::dec << number << std::endl;
std::cout << "Hexadecimal: " << std::hex << number << std::endl;
std::cout << "Octal: " << std::oct << number << std::endl;
// Show base prefixes
std::cout << std::showbase;
std::cout << "With prefixes:" << std::endl;
std::cout << "Decimal: " << std::dec << number << std::endl;
std::cout << "Hexadecimal: " << std::hex << number << std::endl;
std::cout << "Octal: " << std::oct << number << std::endl;
return 0;
}
Output:
Decimal: 255
Hexadecimal: ff
Octal: 377
With prefixes:
Decimal: 255
Hexadecimal: 0xff
Octal: 0377
Error streams: std::cerr and std::clog
std::cerr for error messages
#include <iostream>
int main()
{
int divisor = 0;
if (divisor == 0)
{
std::cerr << "Error: Division by zero!" << std::endl;
return 1; // Return error code
}
std::cout << "Result: " << 10 / divisor << std::endl;
return 0;
}
std::clog for logging
#include <iostream>
int main()
{
std::clog << "Program started" << std::endl;
// Main program logic here
std::cout << "Hello, World!" << std::endl;
std::clog << "Program completed successfully" << std::endl;
return 0;
}
Stream chaining and the return value
Stream operations return a reference to the stream, enabling chaining:
#include <iostream>
int main()
{
// These are equivalent:
std::cout << "Hello, ";
std::cout << "World!";
std::cout << std::endl;
// Chained version:
std::cout << "Hello, " << "World!" << std::endl;
// Reading multiple values:
int a, b, c;
std::cout << "Enter three numbers: ";
std::cin >> a >> b >> c; // Chained input
std::cout << "You entered: " << a << ", " << b << ", " << c << std::endl;
return 0;
}
Sample run:
Hello, World!
Hello, World!
Enter three numbers: 1 2 3
You entered: 1, 2, 3
Working with different data types
Streams automatically handle different data types:
#include <iostream>
#include <string>
int main()
{
// Output different types
int intValue = 42;
double doubleValue = 3.14159;
char charValue = 'A';
std::string stringValue = "Hello";
bool boolValue = true;
std::cout << "Integer: " << intValue << std::endl;
std::cout << "Double: " << doubleValue << std::endl;
std::cout << "Character: " << charValue << std::endl;
std::cout << "String: " << stringValue << std::endl;
std::cout << "Boolean: " << boolValue << std::endl;
// Show boolean values as words instead of 0/1
std::cout << std::boolalpha;
std::cout << "Boolean (text): " << boolValue << std::endl;
return 0;
}
Output:
Integer: 42
Double: 3.14159
Character: A
String: Hello
Boolean: 1
Boolean (text): true
Stream state and error handling
Streams maintain state flags that indicate their current condition:
#include <iostream>
int main()
{
int number;
std::cout << "Enter a number: ";
std::cin >> number;
if (std::cin.good())
{
std::cout << "Successfully read: " << number << std::endl;
}
else
{
std::cerr << "Error: Invalid input!" << std::endl;
// Clear error flags and ignore bad input
std::cin.clear();
std::cin.ignore(10000, '\n');
}
return 0;
}
Sample run with valid input:
Enter a number: 42
Successfully read: 42
Sample run with invalid input:
Enter a number: abc
Error: Invalid input!
Common stream methods
#include <iostream>
#include <string>
int main()
{
// Check stream state
if (std::cin.good()) std::cout << "Stream is good" << std::endl;
if (std::cin.eof()) std::cout << "End of file reached" << std::endl;
if (std::cin.fail()) std::cout << "Last operation failed" << std::endl;
if (std::cin.bad()) std::cout << "Stream is corrupted" << std::endl;
// Get single character
char ch;
std::cout << "Enter a character: ";
ch = std::cin.get(); // Get single character including whitespace
std::cout << "You entered: '" << ch << "'" << std::endl;
// Read entire line
std::string line;
std::cout << "Enter a line: ";
std::cin.ignore(); // Clear newline from previous input
std::getline(std::cin, line);
std::cout << "You entered: " << line << std::endl;
return 0;
}
Best practices for stream I/O
1. Always validate input
#include <iostream>
int getInteger()
{
int value;
while (!(std::cin >> value))
{
std::cout << "Invalid input. Please enter a number: ";
std::cin.clear();
std::cin.ignore(10000, '\n');
}
return value;
}
2. Use appropriate streams for different purposes
std::cout << "Normal output" << std::endl; // Regular output
std::cerr << "Error message" << std::endl; // Error messages
std::clog << "Debug info" << std::endl; // Logging/debugging
3. Flush streams when needed
std::cout << "Processing..." << std::flush; // Force immediate output
// or
std::cout << "Processing..." << std::endl; // Output with newline and flush
Summary
C++ streams provide a unified, type-safe way to handle input and output. The stream operators (<<
and >>
) work with all built-in types and can be overloaded for custom types. Streams maintain state flags for error handling and provide various formatting options. Understanding streams is fundamental to effective C++ I/O programming.
Quiz
- What's the difference between
std::cout
,std::cerr
, andstd::clog
? - Why do stream operations return a reference to the stream?
- What happens when you try to read an integer but the user enters text?
- How can you read a line containing spaces from the console?
- What's the purpose of stream manipulators like
std::setprecision
?
Practice exercises
-
Write a program that reads a student's name and three test scores, then displays them in a formatted table.
-
Create a program that safely reads integers from the user, handling invalid input gracefully.
-
Write a function that formats and displays a floating-point number with exactly 2 decimal places, right-aligned in a field of width 10.
-
Create a program that demonstrates the difference between
>>
andgetline()
when reading strings with spaces.
Explore More Courses
Discover other available courses while this lesson is being prepared.
Browse CoursesLesson Discussion
Share your thoughts and questions