C++ Arrays — 1D, 2D, std::array, std::vector | Tutorials Logic
What is an Array?
An array is a collection of elements of the same type stored in contiguous memory. Elements are accessed by a zero-based index. Arrays are the foundation of most data structures and algorithms in C++.
| Feature | C-style Array | std::array | std::vector |
|---|---|---|---|
| Size | Fixed (compile-time) | Fixed (compile-time) | Dynamic (runtime) |
| Bounds checking | No — undefined behaviour | Yes via at() | Yes via at() |
| STL algorithms | Partial (pointer decay) | Full | Full |
| Memory location | Stack | Stack | Heap |
| Knows its own size | No | Yes (.size()) | Yes (.size()) |
| Prefer in modern C++ | Only for C interop | Fixed-size collections | Most use cases |
1. C-style Arrays — Declaration and Initialization
C-style arrays are inherited from C. The size must be a compile-time constant. They decay to a pointer when passed to functions, losing size information — always pass the size separately.
#include <iostream>
using namespace std;
int main() {
// 1. Declare with size
int arr[5]; // uninitialized — contains garbage
// 2. Declare and initialize
int scores[5] = {85, 92, 78, 95, 88};
// 3. Size inferred from initializer
int primes[] = {2, 3, 5, 7, 11}; // compiler counts: 5 elements
// 4. Partial initialization — rest zero-filled
int zeros[5] = {1, 2}; // {1, 2, 0, 0, 0}
// 5. Zero-initialize all elements
int empty[5] = {}; // {0, 0, 0, 0, 0}
// Access by zero-based index
cout << "First: " << scores[0] << endl; // 85
cout << "Last: " << scores[4] << endl; // 88
// Modify
scores[2] = 80;
// Size: sizeof(array) / sizeof(one element)
int n = sizeof(scores) / sizeof(scores[0]); // 5
// Index-based for loop
int sum = 0;
for (int i = 0; i < n; i++) {
cout << scores[i] << " ";
sum += scores[i];
}
cout << endl;
cout << "Sum: " << sum << endl;
cout << "Avg: " << static_cast<double>(sum) / n << endl;
// Range-based for (C++11) — no index, no size needed
for (int s : scores) cout << s << " ";
cout << endl;
// Pointer arithmetic — arrays decay to pointer to first element
int *ptr = scores;
cout << *(ptr + 2) << endl; // scores[2] = 80
return 0;
}
#include <iostream>
using namespace std;
int main() {
// 2D array: [rows][cols]
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Access: matrix[row][col]
cout << "Center: " << matrix[1][1] << endl; // 5
// Print with nested loops
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
cout << matrix[i][j] << "\t";
}
cout << endl;
}
// Transpose: swap [i][j] with [j][i]
int T[3][3];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
T[j][i] = matrix[i][j];
cout << "\nTransposed:" << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++)
cout << T[i][j] << "\t";
cout << endl;
}
// Row sum
for (int i = 0; i < 3; i++) {
int rowSum = 0;
for (int j = 0; j < 3; j++) rowSum += matrix[i][j];
cout << "Row " << i << " sum: " << rowSum << endl;
}
return 0;
}
Passing Arrays to Functions
When you pass a C-style array to a function, it decays to a pointer — the function receives a pointer to the first element, not a copy. This means the function can modify the original array, and you must pass the size separately.
#include <iostream>
using namespace std;
// Array decays to pointer — size is lost!
// Must pass size separately
void printArray(int arr[], int n) {
for (int i = 0; i < n; i++) cout << arr[i] << " ";
cout << endl;
}
// Modify array elements (pointer, so changes affect original)
void doubleAll(int arr[], int n) {
for (int i = 0; i < n; i++) arr[i] *= 2;
}
// Pass 2D array — must specify all dimensions except first
void print2D(int arr[][3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) cout << arr[i][j] << " ";
cout << endl;
}
}
int main() {
int nums[] = {1, 2, 3, 4, 5};
int n = sizeof(nums) / sizeof(nums[0]);
printArray(nums, n); // 1 2 3 4 5
doubleAll(nums, n);
printArray(nums, n); // 2 4 6 8 10
int grid[2][3] = {{1,2,3},{4,5,6}};
print2D(grid, 2);
return 0;
}
Sorting and Searching Arrays
Common operations on arrays include sorting (bubble sort, STL sort) and searching (linear search O(n), binary search O(log n) on sorted arrays).
#include <iostream>
#include <algorithm>
using namespace std;
// Bubble sort
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n-1; i++) {
for (int j = 0; j < n-i-1; j++) {
if (arr[j] > arr[j+1]) swap(arr[j], arr[j+1]);
}
}
}
// Linear search
int linearSearch(int arr[], int n, int target) {
for (int i = 0; i < n; i++)
if (arr[i] == target) return i;
return -1;
}
// Binary search (array must be sorted)
int binarySearch(int arr[], int n, int target) {
int lo = 0, hi = n - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (arr[mid] == target) return mid;
if (arr[mid] < target) lo = mid + 1;
else hi = mid - 1;
}
return -1;
}
int main() {
int arr[] = {64, 25, 12, 22, 11};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Before: ";
for (int x : arr) cout << x << " ";
cout << endl;
bubbleSort(arr, n);
cout << "After: ";
for (int x : arr) cout << x << " ";
cout << endl; // 11 12 22 25 64
cout << "Linear search 22: index " << linearSearch(arr, n, 22) << endl; // 2
cout << "Binary search 25: index " << binarySearch(arr, n, 25) << endl; // 3
// STL sort (fastest — introsort)
int arr2[] = {5, 3, 8, 1, 9, 2};
sort(arr2, arr2 + 6);
for (int x : arr2) cout << x << " "; // 1 2 3 5 8 9
cout << endl;
return 0;
}
2. std::array — Fixed-size Modern Array
std::array (C++11, from <array>) is a thin wrapper around a C-style array that adds size awareness, bounds checking, and full STL compatibility — with zero runtime overhead. Use it whenever the size is known at compile time.
#include <iostream>
#include <array>
#include <algorithm>
#include <numeric>
using namespace std;
int main() {
// std::array<type, size> — fixed size, stack allocated
array<int, 5> nums = {3, 1, 4, 1, 5};
// Size — always knows it
cout << "Size: " << nums.size() << endl; // 5
cout << "Front: " << nums.front() << endl; // 3
cout << "Back: " << nums.back() << endl; // 5
// Safe access — throws std::out_of_range
try {
cout << nums.at(10) << endl; // throws!
} catch (const out_of_range &e) {
cout << "Out of range: " << e.what() << endl;
}
// STL algorithms work directly
sort(nums.begin(), nums.end());
for (auto n : nums) cout << n << " "; // 1 1 3 4 5
cout << endl;
// Sum with accumulate
int sum = accumulate(nums.begin(), nums.end(), 0);
cout << "Sum: " << sum << endl; // 14
// Fill all elements
nums.fill(0);
for (auto n : nums) cout << n << " "; // 0 0 0 0 0
cout << endl;
// Pass to function — size is part of the type, no decay
auto printArr = [](const array<int, 5> &a) {
for (auto x : a) cout << x << " ";
cout << endl;
};
printArr(nums);
return 0;
}
3. std::vector — Dynamic Array
std::vector (from <vector>) is the most commonly used container in C++. It is a dynamic array that grows automatically. Elements are stored contiguously in heap memory. Use it as your default container unless you have a specific reason not to.
Internally, when a vector runs out of capacity it allocates a new larger block (typically 2x), copies all elements, and frees the old block. Use reserve() to pre-allocate and avoid repeated reallocations.
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
int main() {
// Create vectors
vector<int> v1 = {5, 3, 8, 1}; // initializer list
vector<int> v2(5, 0); // 5 elements, all 0
vector<int> v3(v1.begin(), v1.end()); // copy from another
// Add / remove elements
v1.push_back(9); // add to end: {5,3,8,1,9}
v1.push_back(2); // {5,3,8,1,9,2}
v1.pop_back(); // remove last: {5,3,8,1,9}
cout << "Size: " << v1.size() << endl; // 5
cout << "Capacity: " << v1.capacity() << endl; // >= 5
// Insert at position
v1.insert(v1.begin() + 2, 99); // insert 99 at index 2
// Erase by index
v1.erase(v1.begin() + 2); // remove element at index 2
// Remove all occurrences of a value (erase-remove idiom)
v1.push_back(5);
v1.erase(remove(v1.begin(), v1.end(), 5), v1.end());
// Sort
sort(v1.begin(), v1.end());
for (auto n : v1) cout << n << " ";
cout << endl;
// Find
auto it = find(v1.begin(), v1.end(), 8);
if (it != v1.end())
cout << "Found 8 at index " << (it - v1.begin()) << endl;
// Sum
int sum = accumulate(v1.begin(), v1.end(), 0);
cout << "Sum: " << sum << endl;
// 2D vector (dynamic matrix)
int rows = 3, cols = 4;
vector<vector<int>> mat(rows, vector<int>(cols, 0));
mat[1][2] = 42;
cout << "mat[1][2] = " << mat[1][2] << endl; // 42
return 0;
}
// std::vector key methods reference
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {10, 20, 30, 40, 50};
// Element access
cout << v[2] << endl; // 30 — no bounds check
cout << v.at(2) << endl; // 30 — throws if out of range
cout << v.front() << endl; // 10
cout << v.back() << endl; // 50
// Size / capacity
cout << v.size() << endl; // 5
cout << v.empty() << endl; // 0 (false)
cout << v.capacity() << endl; // >= 5
v.reserve(100); // pre-allocate — avoids reallocations
v.shrink_to_fit(); // release excess capacity
// Modifiers
v.push_back(60);
v.emplace_back(70); // construct in-place (faster than push_back for objects)
v.pop_back();
v.insert(v.begin(), 5); // insert at front
v.erase(v.begin()); // erase front
v.clear(); // remove all elements (size=0, capacity unchanged)
v.resize(3, 99); // resize to 3, fill new elements with 99
for (auto x : v) cout << x << " "; // 99 99 99
cout << endl;
return 0;
}
STL Algorithms with Arrays and Vectors
The <algorithm> and <numeric> headers provide powerful ready-made algorithms that work on any container with iterators — including arrays and vectors.
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
int main() {
vector<int> v = {5, 2, 8, 1, 9, 3, 7, 4, 6};
// sort ascending
sort(v.begin(), v.end());
// sort descending
sort(v.begin(), v.end(), greater<int>());
// min and max element
auto mn = *min_element(v.begin(), v.end());
auto mx = *max_element(v.begin(), v.end());
cout << "Min: " << mn << ", Max: " << mx << endl;
// count occurrences
vector<int> nums = {1,2,2,3,2,4,2};
cout << "Count of 2: " << count(nums.begin(), nums.end(), 2) << endl; // 4
// sum and product
int sum = accumulate(v.begin(), v.end(), 0);
int prod = accumulate(v.begin(), v.end(), 1, multiplies<int>());
cout << "Sum: " << sum << ", Product: " << prod << endl;
// reverse
reverse(v.begin(), v.end());
// rotate — bring element at index 2 to front
rotate(v.begin(), v.begin() + 2, v.end());
// unique — remove consecutive duplicates (sort first)
sort(nums.begin(), nums.end());
nums.erase(unique(nums.begin(), nums.end()), nums.end());
for (auto x : nums) cout << x << " "; // 1 2 3 4
cout << endl;
// fill and iota
vector<int> a(5);
fill(a.begin(), a.end(), 7); // {7,7,7,7,7}
iota(a.begin(), a.end(), 1); // {1,2,3,4,5}
for (auto x : a) cout << x << " ";
cout << endl;
return 0;
}
std::vector Key Methods — Quick Reference
| Method | Description | Complexity |
|---|---|---|
push_back(val) | Add element to end | O(1) amortized |
emplace_back(args) | Construct element in-place at end | O(1) amortized |
pop_back() | Remove last element | O(1) |
insert(pos, val) | Insert at iterator position | O(n) |
erase(pos) | Remove element at iterator position | O(n) |
at(i) | Access with bounds check (throws) | O(1) |
operator[](i) | Access without bounds check | O(1) |
front() / back() | First / last element | O(1) |
size() | Number of elements | O(1) |
capacity() | Allocated storage | O(1) |
reserve(n) | Pre-allocate for n elements | O(n) |
resize(n) | Change size (add/remove elements) | O(n) |
clear() | Remove all elements | O(n) |
empty() | Check if size == 0 | O(1) |
begin() / end() | Iterators to first / past-last | O(1) |
When to Use Which?
| Situation | Use | Reason |
|---|---|---|
| Size known at compile time, no overhead | std::array | Stack allocated, zero overhead, safe |
| Size unknown or changes at runtime | std::vector | Dynamic, grows automatically |
| Interfacing with C APIs | C-style array or v.data() | C APIs expect raw pointers |
| Frequent insert/delete in middle | std::list or std::deque | O(1) insert vs O(n) for vector |
| Default choice | std::vector | Most flexible, best cache performance |
Level Up Your C plus plus Skills
Master C plus plus with these hand-picked resources