Hi everyone 
In this tutorial we will talk about Array
So, What is Array actually?
Array is a sequential container of C++ STL that wraps a fixed-size contiguous array. The size of an array is decided at compile time and cannot be changed once the array is declared.
We all know the classic C-style array (int arr[10];). STL array is basically a thin wrapper around it — with the same fixed-size nature, the same contiguous memory layout, and the same O(1) random access. But unlike the C-style array, STL array gives us proper STL-style methods like size(), front(), back(), begin(), end(), and so on. It also knows its own size (C-style arrays forget their size the moment you pass them to a function).
Because STL array has a fixed size, it does not have methods like push_back(), pop_back(), insert(), erase(), or resize(). If we need to grow or shrink, we should use vector or deque instead.
Array’s underlying data structure is a plain C-style array. There is no extra pointer or heap allocation — the data sits right inside the array object itself, so it is typically allocated on the stack.
💡 Note on availability — STL array is a C++11 feature. Any modern compiler supports it with the
-std=c++11flag (or newer).
Header File Inclusion for array
#include <array>
Declaration & Initialization
An STL array takes two template parameters — the element type, and the fixed size.
Declaring an uninitialized array —
array <int, 5> mark;
Here, the element type is int and the size is 5. The elements are uninitialized (they will contain garbage values until we assign to them).
Declaring an array with values —
array <int, 5> mark = { 85, 90, 78, 92, 88 };
After Initialization mark will look like this —
| 85 | 90 | 78 | 92 | 88 |
Declaring an array with fewer values than size —
If we provide fewer values than the declared size, the remaining elements are value-initialized (zero for built-in types) —
array <int, 5> mark = { 85, 90 };
After Initialization mark will look like this —
| 85 | 90 | 0 | 0 | 0 |
Declaring a zero-initialized array —
We can zero-initialize the whole array by giving it an empty initializer list —
array <int, 5> mark = {};
All five elements will be 0.
Declaring arrays of different types —
Element type can be anything —
array <double, 4> scores = { 95.5, 88.0, 72.5, 60.0 };
array <string, 3> nameList = { "Imran", "Linkon", "Sakib" };
array <pair<int, int>, 2> points = { {1, 2}, {3, 4} };
💡 Quick tip on size — The size of an STL array is part of its type. That means
array<int, 5>andarray<int, 6>are two completely different types, and we cannot assign one to the other.
Accessing the element
[ ] subscript operator
Just like a C-style array, STL array supports the [ ] subscript operator for random access —
array <int, 5> mark = { 85, 90, 78, 92, 88 };
// the following line will print 78 as output
cout << mark[2] << endl;
// the following line will print 85 as output
cout << mark[0] << endl;
at() method
For accessing an element, at() method works the same as the [ ] operator — but with bounds checking. If we pass an index out of range, at() throws an out_of_range exception, while [ ] gives us undefined behavior.
// the following line will print 78 as output
cout << mark.at(2) << endl;
// the following line will throw out_of_range exception
cout << mark.at(10) << endl;
at() is also useful for pointer variables, since pointer variables can not use [ ] subscript operator directly —
array <int, 5> *pArr = &mark;
// the following line will print 78 as output
cout << pArr->at(2) << endl;
front() and back()
We can easily access the first and last element of an array using front() and back() methods —
// front() method for accessing the first element
// the following line will print 85 as output
cout << mark.front() << endl;
// back() method for accessing the last element
// the following line will print 88 as output
cout << mark.back() << endl;
data() method
data() returns a raw pointer to the first element of the underlying C-style array. This is useful when we need to pass the array to a C API or a function that expects a plain pointer —
int *rawPtr = mark.data();
// now rawPtr points to mark[0]
cout << rawPtr[0] << endl;
cout << rawPtr[3] << endl;
Output will be —
85
92
Modifying the elements
Since STL array has a fixed size, we cannot add or remove elements. But we can freely modify the existing ones — using the [ ] operator, at() method, front(), or back() —
array <int, 5> mark = { 85, 90, 78, 92, 88 };
mark[0] = 100;
mark.at(2) = 80;
mark.back() = 95;
After modification mark will look like this —
| 100 | 90 | 80 | 92 | 95 |
fill() method
fill() is a handy method that assigns the same value to every element of the array in one call —
array <int, 5> mark;
mark.fill(0);
After fill(0) mark will look like this —
| 0 | 0 | 0 | 0 | 0 |
This is especially useful when we want to reset a counting array or a visited array to 0 or some default value.
Size and Empty
array <int, 5> mark = { 85, 90, 78, 92, 88 };
cout << mark.size() << endl;
cout << mark.max_size() << endl;
if (mark.empty())
{
cout << "Array is empty" << endl;
}
else
{
cout << "Array is not empty" << endl;
}
Output will be —
5
5
Array is not empty
💡 Note on size(), max_size(), and empty() — Since the size of an STL array is fixed at compile time,
size()andmax_size()always return the same value. Andempty()returns true only when the array size is 0 (declared asarray<int, 0>) — for a non-zero-sized array, it always returns false.
Iterating through an array
Range-based for loop
The cleanest way to iterate through an array is using a range-based for loop —
array <int, 5> mark = { 85, 90, 78, 92, 88 };
for (auto &value : mark)
{
cout << value << " ";
}
Output will be – 85 90 78 92 88
Using index
Just like a C-style array, we can iterate with a simple for loop and indices —
for (int i = 0; i < mark.size(); i++)
{
cout << mark[i] << " ";
}
Using iterator
We can also iterate using iterators directly —
array <int, 5>::iterator it;
for (it = mark.begin(); it != mark.end(); it++)
{
cout << *it << " ";
}
Swapping
swap() method
STL array has a method named swap(), which swaps values element-by-element between two arrays. The two arrays must have the same type and the same size —
array <int, 4> arrOne = { 1, 2, 3, 4 };
array <int, 4> arrTwo = { 10, 20, 30, 40 };
arrOne will look like this —
| 1 | 2 | 3 | 4 |
arrTwo will look like this —
| 10 | 20 | 30 | 40 |
Now, let’s swap the elements of two arrays —
// swapping values between two arrays
arrOne.swap(arrTwo);
After Swapping arrOne will look like this —
| 10 | 20 | 30 | 40 |
After Swapping arrTwo will look like this —
| 1 | 2 | 3 | 4 |
💡 Note on swap() cost — Unlike vector or deque (where swap is O(1) because they only swap internal pointers), array’s swap() is O(n). Since the elements live directly inside the array object, swap has to actually copy each element one by one.
Array Object Operations
Copying an array to another
For copying an array to another, we can simply use the assignment operator —
array <int, 4> oldArr = { 1, 2, 3, 4 };
array <int, 4> newArr;
// now copying all oldArr elements to newArr
newArr = oldArr;
Comparing two arrays
Array supports all comparison operators — ==, !=, <, >, <=, >=. Two arrays are compared element-by-element —
array <int, 3> arrOne = { 1, 2, 3 };
array <int, 3> arrTwo = { 1, 2, 3 };
array <int, 3> arrThree = { 1, 2, 4 };
if (arrOne == arrTwo)
{
cout << "arrOne and arrTwo are equal" << endl;
}
if (arrOne < arrThree)
{
cout << "arrOne is less than arrThree" << endl;
}
Output will be —
arrOne and arrTwo are equal
arrOne is less than arrThree
Structured Bindings (C++17)
Since C++17, STL array plays nicely with structured bindings — we can unpack the array into individual named variables in a single line —
array <int, 3> point = { 10, 20, 30 };
auto [x, y, z] = point;
cout << x << " " << y << " " << z << endl;
Output will be – 10 20 30
This is especially handy when we return an array from a function and want to name the individual values right at the call site.
Tuple Interface
STL array also supports the tuple interface — we can use std::get<N>(), std::tuple_size, and std::tuple_element on it, just like a tuple —
array <int, 3> point = { 10, 20, 30 };
// get the element at compile-time index 1
cout << get<1>(point) << endl;
// get the size at compile time
cout << tuple_size<decltype(point)>::value << endl;
Output will be —
20
3
💡 Quick tip on get vs [ ] —
get<N>()uses a compile-time index, while[ ]uses a run-time index. This meansget<N>()can catch out-of-range errors at compile time, while[ ]can only fail at run time.
Array vs C-style array vs Vector
This is the biggest question when picking between these three — so it is worth laying them side by side.
| Property | array | C-style array | vector |
|---|---|---|---|
| Size | Fixed at compile time | Fixed at compile time | Dynamic (changes at run time) |
| Memory location | Typically stack | Typically stack | Heap (pointer on stack) |
| Knows its own size | Yes (size() method) | No (decays to pointer) | Yes (size() method) |
| STL iterator support | Full | Via raw pointers | Full |
| Bounds checking | at() throws | None | at() throws |
| Copy with = | Yes (element-wise) | No (pointer copy only) | Yes (deep copy) |
| Runtime overhead vs raw array | Zero | Baseline | Small (heap allocation) |
| Use when | Size is known at compile time and we want STL features | Working with legacy code or C APIs | Size is dynamic or unknown |
Time Complexity
| Operation | Description | Time Complexity |
|---|---|---|
| [ ] or at() | Random access | O(1) |
| front() | Accessing the first element | O(1) |
| back() | Accessing the last element | O(1) |
| data() | Returns a raw pointer to the first element | O(1) |
| begin() / end() | Iterators to the beginning and end | O(1) |
| rbegin() / rend() | Reverse iterators | O(1) |
| size() | Returns the fixed size of the array | O(1) |
| max_size() | Returns the maximum number of elements (equal to size) | O(1) |
| empty() | Returns true if array size is 0 | O(1) |
| fill() | Assigns the same value to every element | O(n) |
| swap() | Swap elements between two arrays | O(n) |
| == / != / < / > / <= / >= | Element-wise comparison | O(n) |
| get<N>() | Compile-time indexed access | O(1) |
Applications
-
-
-
- Storing a fixed set of values that never change size (e.g., days of week, RGB colors, chess board)
- Lookup tables and sine/cosine tables computed at program start
- Visited arrays and counting arrays in competitive programming when the size is known
- Representing mathematical entities with a fixed dimension (2D points, 3D vectors, matrices)
- Passing a known-size buffer to a C API through the data() pointer
- Embedded systems and memory-constrained environments (no heap allocation)
- Drop-in replacement for C-style arrays when we want STL features like size() and bounds checking
- Returning multiple values from a function as a single named unit
-
-
In the next tutorial we will talk about another useful STL container.
Until then
Happy Coding