C++ Programming Tutorial
Learn modern C++ step-by-step — from basics to advanced features like templates, STL, and smart pointers. Clear explanations with practical, runnable examples.
C++ Arrays and Vectors
C++ offers three main sequential containers: C-style arrays (fixed, unsafe), std::array (fixed, safe), and std::vector (dynamic, safe). Modern C++ strongly favors std::vector for most use cases.
C-Style Arrays
c_arrays.cpp
#include <iostream>
int main() {
// Fixed-size, stack-allocated
int numbers[5] = {10, 20, 30, 40, 50};
// Access by index (0-based)
std::cout << numbers[0] << "
"; // 10
std::cout << numbers[4] << "
"; // 50
// Iterate
for (int i = 0; i < 5; ++i) {
std::cout << numbers[i] << " ";
}
std::cout << "
";
// WARNING: no bounds checking!
// numbers[10] = 99; // undefined behavior — may crash or corrupt memory
// Size must be known at compile time
constexpr int SIZE = 3;
double values[SIZE] = {1.1, 2.2, 3.3};
return 0;
}std::array (C++11) — Fixed Size, Safe
std_array.cpp
#include <iostream>
#include <array>
#include <algorithm>
int main() {
// Type-safe, knows its own size, supports STL algorithms
std::array<int, 5> nums{10, 20, 30, 40, 50};
std::cout << "Size: " << nums.size() << "
"; // 5
std::cout << "First: " << nums.front() << "
"; // 10
std::cout << "Last: " << nums.back() << "
"; // 50
// Bounds-checked access with .at()
// nums.at(10); // throws std::out_of_range
// Works with algorithms
std::sort(nums.begin(), nums.end());
std::reverse(nums.begin(), nums.end());
// Range-based for
for (int n : nums) {
std::cout << n << " ";
}
std::cout << "
";
return 0;
}std::vector — Dynamic Size (Most Used)
vector.cpp
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
// Create and initialize
std::vector<int> nums{1, 2, 3, 4, 5};
std::vector<std::string> names{"Alice", "Bob", "Charlie"};
std::vector<double> zeros(10, 0.0); // 10 elements, all 0.0
// Add elements
nums.push_back(6);
nums.push_back(7);
nums.emplace_back(8); // construct in-place (more efficient)
// Access elements
std::cout << nums[0] << "
"; // 1 (no bounds check)
std::cout << nums.at(2) << "
"; // 3 (throws if out of range)
std::cout << nums.front() << "
"; // 1
std::cout << nums.back() << "
"; // 8
// Size and capacity
std::cout << "Size: " << nums.size() << "
";
std::cout << "Empty: " << nums.empty() << "
";
// Remove elements
nums.pop_back(); // remove last
nums.erase(nums.begin() + 1); // remove at index 1
// Insert
nums.insert(nums.begin(), 0); // insert 0 at front
// Iterate
for (const auto& n : nums) {
std::cout << n << " ";
}
std::cout << "
";
// Sort
std::sort(nums.begin(), nums.end());
// Find
auto it = std::find(nums.begin(), nums.end(), 5);
if (it != nums.end()) {
std::cout << "Found 5 at index " << (it - nums.begin()) << "
";
}
return 0;
}Common Vector Operations
vector_ops.cpp
#include <iostream>
#include <vector>
#include <numeric> // for accumulate
#include <algorithm> // for sort, min/max_element, count
int main() {
std::vector<int> v{5, 2, 8, 1, 9, 3, 7};
// Sum all elements
int sum = std::accumulate(v.begin(), v.end(), 0);
std::cout << "Sum: " << sum << "
"; // 35
// Min and max
auto [min_it, max_it] = std::minmax_element(v.begin(), v.end());
std::cout << "Min: " << *min_it << ", Max: " << *max_it << "
";
// Count occurrences
int count = std::count(v.begin(), v.end(), 5);
// Remove duplicates (sort first)
std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()), v.end());
// Filter: keep only values > 3
std::vector<int> filtered;
std::copy_if(v.begin(), v.end(), std::back_inserter(filtered),
[](int x) { return x > 3; });
for (int n : filtered) std::cout << n << " "; // 5 7 8 9
std::cout << "
";
return 0;
}Comparison Table
| Feature | C array | std::array | std::vector |
|---|---|---|---|
| Size | Fixed (compile-time) | Fixed (compile-time) | Dynamic (runtime) |
| Bounds checking | None | .at() method | .at() method |
| Knows its size | No | Yes (.size()) | Yes (.size()) |
| STL compatible | Partially | Yes | Yes |
| Memory | Stack | Stack | Heap (auto-managed) |
| When to use | Rarely (legacy code) | Fixed collections | Almost everything |
- Default to
std::vector— it handles 95% of sequential container needs. - Use
std::arraywhen the size is known at compile time and you want stack allocation. - Avoid C-style arrays in new code — they decay to pointers and lose size information.
- Reserve capacity with
v.reserve(n)if you know the approximate size upfront to avoid reallocations.
Keep Practicing
Use the online compiler to run every example and experiment with modifications. The best way to learn C++ is by writing code — even small programs build strong foundations.