Arrays and Vectors in C++
Arrays and Vectors in C++ Interview with follow-up questions
1. What is the difference between arrays and vectors in C++?
Arrays and vectors are both sequential containers, but they differ significantly in flexibility, safety, and interface.
Size: C-style arrays have a fixed size determined at compile time. Vectors (
std::vector) are dynamic — they grow and shrink at runtime automatically.Memory management: C-style arrays allocated on the stack are limited by stack size and cannot be resized. Vectors manage heap memory internally and handle allocation and deallocation automatically, eliminating manual
new/delete.Type safety and bounds checking: C-style arrays decay to pointers, losing size information. In debug builds,
vector::at()throwsstd::out_of_rangeon invalid access;operator[]has no such check.std::array(fixed-size, stack-allocated) solves the decay problem for fixed sizes.Interface: Vectors provide a rich STL interface —
push_back,emplace_back,erase,insert, iterators, range-based for, and compatibility with all STL algorithms. C-style arrays have none of this.Modern alternative —
std::span(C++20): When you need to pass an array or vector to a function without copying, preferstd::span. It is a non-owning view over any contiguous sequence (raw array,std::array, orstd::vector) and preserves size information.
void process(std::span data) {
for (int x : data) { /* ... */ }
}
int arr[] = {1, 2, 3};
std::vector vec = {4, 5, 6};
process(arr); // works
process(vec); // works
- Performance: For small, fixed-size collections,
std::arraymatches raw-array performance with zero overhead and full STL compatibility.std::vectorhas a slight overhead from the heap allocation but is generally negligible and preferred for runtime-sized collections.
When to use each:
- Use
std::vectorwhen size is unknown at compile time or may change. - Use
std::arrayas a safer, STL-compatible replacement for fixed-size C-style arrays. - Use
std::spanto accept any contiguous range in function parameters. - Avoid raw C-style arrays in new code unless interfacing with a C API.
Follow-up 1
Can you explain with an example?
Sure! Here's an example that demonstrates the difference between arrays and vectors:
#include
#include
int main() {
// Array
int arr[3] = {1, 2, 3};
arr[0] = 4; // Modifying an element
std::cout << arr[0] << std::endl; // Accessing an element
// Vector
std::vector vec = {1, 2, 3};
vec[0] = 4; // Modifying an element
std::cout << vec[0] << std::endl; // Accessing an element
return 0;
}
In this example, we create an array arr and a vector vec, both containing three elements. We then modify the first element of both the array and the vector, and finally, we print the first element of both the array and the vector. As you can see, the syntax for accessing and modifying elements is the same for both arrays and vectors.
Follow-up 2
How does memory allocation differ between the two?
The memory allocation for arrays and vectors differs in the following ways:
Arrays: Arrays are allocated on the stack. The memory for an array is allocated at compile-time and is deallocated automatically when the array goes out of scope. The size of the array must be known at compile-time, and it cannot be resized.
Vectors: Vectors are allocated on the heap. The memory for a vector is allocated at runtime using dynamic memory allocation (usually
newormalloc). The size of the vector can be changed dynamically using theresize()method. The memory for the vector must be deallocated manually using thedeleteorfreefunction when it is no longer needed.
It's important to note that vectors handle memory allocation and deallocation automatically, making them more convenient to use and reducing the risk of memory leaks compared to arrays.
Follow-up 3
In what scenarios would you prefer to use vectors over arrays?
Vectors are preferred over arrays in the following scenarios:
Dynamic Size: If the size of the collection is not known at compile-time or may change during runtime, vectors are a better choice. Vectors can be resized dynamically using the
resize()method, while arrays have a fixed size.Convenience: Vectors provide built-in methods for adding, removing, and accessing elements, as well as for resizing and sorting the vector. This makes them more convenient to use compared to arrays, which require manual memory management and do not provide these functionalities.
Safety: Vectors handle memory allocation and deallocation automatically, reducing the risk of memory leaks and buffer overflows compared to arrays.
Performance is not a critical factor: While arrays generally have better performance than vectors, especially for small sizes, the performance difference becomes negligible for larger sizes. Therefore, if performance is not a critical factor, the convenience and flexibility of vectors make them a preferred choice over arrays.
2. How do you declare and initialize an array in C++?
In C++, arrays can be declared and initialized in several ways depending on whether you need a fixed-size compile-time array or a safer modern alternative.
C-style array (traditional)
int numbers[5] = {1, 2, 3, 4, 5};
If fewer initializers are provided than the declared size, the remaining elements are zero-initialized:
int numbers[5] = {1, 2}; // {1, 2, 0, 0, 0}
You can omit the size when providing a full initializer list, and the compiler deduces it:
int numbers[] = {1, 2, 3, 4, 5}; // size deduced as 5
std::array (preferred for fixed-size collections)
std::array is the modern replacement for C-style arrays. It has the same stack-allocated, zero-overhead characteristics but preserves size information, supports STL algorithms, and does not decay to a pointer:
#include
std::array numbers = {1, 2, 3, 4, 5};
std::array zeros{}; // value-initialized to all zeros
std::vector (for runtime-sized arrays)
When the size is not known at compile time, use std::vector:
#include
std::vector numbers = {1, 2, 3, 4, 5};
std::vector repeated(5, 0); // five zeros
std::span (C++20, for non-owning views)
To pass any contiguous array to a function without copying or losing size:
#include <span>
void print(std::span data) {
for (int x : data) std::cout << x << ' ';
}
In new code, prefer std::array over C-style arrays for fixed sizes, and std::vector when the size is dynamic.
Follow-up 1
What happens if you don't initialize an array?
If you don't initialize an array in C++, the elements of the array will have indeterminate values. These values are unpredictable and can be any garbage value that was previously stored in the memory location allocated for the array. It is always recommended to initialize an array to avoid accessing uninitialized values.
Follow-up 2
Can you declare an array without specifying its size?
In C++, you cannot declare an array without specifying its size. The size of an array must be known at compile-time. However, you can use dynamic memory allocation to create an array whose size is determined at runtime. This can be done using the 'new' operator to allocate memory for the array and then assigning the address of the allocated memory to a pointer variable.
Follow-up 3
What is the default value of elements in an array if not initialized?
If you don't initialize the elements of an array in C++, they will have indeterminate values. These values are unpredictable and can be any garbage value that was previously stored in the memory location allocated for the array. It is always recommended to initialize the elements of an array to avoid accessing uninitialized values.
3. What are the operations that can be performed on vectors in C++?
Vectors in C++ (std::vector) support a wide range of operations. The key ones an interviewer expects you to know:
Adding elements
push_back(val)— appends an element; amortized O(1).emplace_back(args...)— constructs in-place at the back; avoids an extra copy/move compared topush_back.insert(pos, val)— inserts before an iterator position; O(n).
Removing elements
pop_back()— removes the last element; O(1).erase(pos)/erase(first, last)— removes one or a range of elements; O(n).clear()— removes all elements; does not release memory (capacity unchanged).
Accessing elements
operator[]— unchecked access; undefined behavior on out-of-bounds.at(i)— bounds-checked; throwsstd::out_of_range.front()/back()— first and last elements.data()— raw pointer to the underlying array; useful when passing to C APIs.
Size and capacity
size()— number of elements currently stored.capacity()— number of elements that fit before reallocation.resize(n)— changes the logical size; new elements are value-initialized.reserve(n)— pre-allocates capacity without changing size; avoids repeated reallocations.shrink_to_fit()— requests capacity to be reduced to size (non-binding).empty()— returnstrueif size is zero.
Iteration
- Range-based for:
for (auto& x : v) - STL iterators:
v.begin(),v.end(),v.rbegin(),v.rend() - Compatible with all `
functions such asstd::sort,std::find,std::transform`.
Algorithms (C++20 Ranges)
With C++20 ranges, you can compose operations without naming iterators:
#include
#include
std::vector v = {5, 3, 1, 4, 2};
std::ranges::sort(v); // sort in place
auto evens = v | std::views::filter([](int x){ return x % 2 == 0; });
Example — common operations
#include
#include
std::vector v;
v.reserve(10); // pre-allocate
v.push_back(3);
v.emplace_back(7);
v.insert(v.begin(), 1); // insert at front
std::sort(v.begin(), v.end());
v.erase(v.begin()); // remove first element
Gotcha: push_back and insert can invalidate all iterators and pointers into the vector if a reallocation occurs. Use reserve up front when the eventual size is known.
Follow-up 1
How do you add and remove elements from a vector?
To add elements to a vector, you can use the push_back() function to add elements at the end of the vector. For example:
#include
#include
int main() {
std::vector myVector;
myVector.push_back(10);
myVector.push_back(20);
myVector.push_back(30);
return 0;
}```
To remove elements from a vector, you can use the `pop_back()` function to remove the last element of the vector. For example:
```cpp
#include
#include
int main() {
std::vector myVector;
myVector.push_back(10);
myVector.push_back(20);
myVector.push_back(30);
myVector.pop_back();
return 0;
}```
Follow-up 2
How do you access elements in a vector?
You can access elements in a vector using the subscript operator [] or the at() function. For example:
#include
#include
int main() {
std::vector myVector {10, 20, 30};
std::cout << myVector[0] << std::endl; // Output: 10
std::cout << myVector.at(1) << std::endl; // Output: 20
return 0;
}```
Follow-up 3
Can you sort a vector? If so, how?
Yes, you can sort a vector in C++. You can use the sort() function from the `` library to sort the elements of a vector in ascending order. For example:
#include
#include
#include
int main() {
std::vector myVector {30, 10, 20};
std::sort(myVector.begin(), myVector.end());
for (int num : myVector) {
std::cout << num << " ";
}
// Output: 10 20 30
return 0;
}```
If you want to sort the vector in descending order, you can use the `greater` function as the third argument of the `sort()` function. For example:
```cpp
#include
#include
#include
int main() {
std::vector myVector {30, 10, 20};
std::sort(myVector.begin(), myVector.end(), std::greater());
for (int num : myVector) {
std::cout << num << " ";
}
// Output: 30 20 10
return 0;
}```
4. How do you handle multidimensional arrays in C++?
C++ provides several approaches for multidimensional arrays, each with different trade-offs.
C-style 2D arrays (fixed dimensions)
Declare by specifying all dimensions at compile time:
int arr[3][4]; // 3 rows, 4 columns, all on the stack
arr[1][2] = 42; // row 1, column 2
You can initialize inline:
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
Gotcha with function parameters: C-style 2D arrays decay to int (*)[4] — only the outermost dimension is lost. You must specify all inner dimensions in the parameter:
void process(int arr[][4], int rows); // columns must be specified
This makes the interface fragile. Prefer the modern alternatives below.
std::array for fixed-size 2D arrays
#include
using Matrix2x3 = std::array, 2>;
Matrix2x3 m = {{{1, 2, 3}, {4, 5, 6}}};
m[0][1] = 99;
No pointer decay, full STL compatibility, and size is always known.
std::vector for runtime-sized 2D arrays
#include
int rows = 3, cols = 4;
std::vector> grid(rows, std::vector(cols, 0));
grid[1][2] = 42;
This works but has non-contiguous memory (each inner vector allocates separately). For performance-critical code, use a flattened 1D vector and compute the index manually:
std::vector flat(rows * cols, 0);
flat[i * cols + j] = 42; // equivalent to grid[i][j]
A flattened layout is cache-friendly because all data is contiguous.
std::span for viewing existing 2D data (C++20)
std::span can view a contiguous block but is inherently 1D. Use std::mdspan (C++23) for a true multidimensional non-owning view:
#include
std::vector data(12);
auto view = std::mdspan(data.data(), 3, 4); // 3×4 view
view[1, 2] = 42; // C++23 multidimensional subscript operator
Summary of choices:
int arr[M][N]orstd::array,M>— fixed compile-time dimensions, stack allocated.std::vector>— fully dynamic but non-contiguous.- Flattened
std::vectorwith manual indexing — dynamic and cache-friendly. std::mdspan(C++23) — non-owning multidimensional view over any contiguous storage; the preferred modern approach when available.
Follow-up 1
How do you access elements in a multidimensional array?
To access elements in a multidimensional array, you can use the array indices. For example, to access the element at the i-th row and j-th column of a 2-dimensional array arr, you can use arr[i][j]. Similarly, for a 3-dimensional array, you can use arr[i][j][k] to access the element at the i-th row, j-th column, and k-th depth.
Follow-up 2
Can you explain with an example?
Sure! Here's an example of how to declare and initialize a 2-dimensional array in C++:
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
This creates a 2-dimensional array with 3 rows and 4 columns. Each element can be accessed using the array indices, such as arr[1][2] to access the element at the second row and third column, which is 7.
Follow-up 3
What is the memory layout of a multidimensional array?
In C++, a multidimensional array is stored in a contiguous block of memory. For a 2-dimensional array, the elements are stored row by row. That means, the elements of the first row are stored first, followed by the elements of the second row, and so on. Similarly, for a 3-dimensional array, the elements are stored in a row-major order, where the elements of each row are stored first, followed by the elements of each column, and then the elements of each depth.
5. What is the significance of the size() and capacity() functions in vectors in C++?
size() and capacity() represent two distinct but related properties of a std::vector:
size()returns the number of elements currently stored in the vector — the elements that are actually present and accessible.capacity()returns the total number of elements the vector can hold in its currently allocated memory before it needs to allocate a new, larger block.
The invariant is always size() <= capacity().
Why they differ — the growth strategy
When you call push_back and size() == capacity(), the vector must reallocate. It typically doubles the capacity (implementation-defined, but doubling is standard in libstdc++ and libc++), copies or moves all existing elements to the new buffer, and then inserts the new element. This makes the amortized cost of push_back O(1) while avoiding a reallocation on every insertion.
std::vector v;
// size=0, capacity=0
v.push_back(1);
// size=1, capacity=1 (or more, implementation-defined)
v.push_back(2);
// size=2, capacity=2 (or more)
v.push_back(3);
// size=3, capacity=4 (typical doubling)
std::cout << v.size(); // 3
std::cout << v.capacity(); // 4 (implementation-defined)
reserve(n) — pre-allocating capacity
If you know the approximate final size, call reserve to avoid repeated reallocations:
std::vector v;
v.reserve(1000); // capacity >= 1000, size still 0
// 1000 push_backs cause zero reallocations
This is one of the most impactful micro-optimizations for vectors.
resize(n) vs reserve(n)
reserve(n)changes capacity only — no new elements are created, size is unchanged.resize(n)changes the logical size — new elements are value-initialized; capacity is increased if needed.
shrink_to_fit()
Requests that excess capacity be released so capacity approaches size. The request is non-binding (the implementation may ignore it), but it is useful for long-lived vectors that held temporarily large data.
v.shrink_to_fit(); // capacity may drop to size()
Interview gotcha: Every reallocation invalidates all iterators, pointers, and references into the vector. Storing a pointer or iterator to a vector element and then calling push_back is a classic source of undefined behavior — avoided by calling reserve first.
Follow-up 1
What is the difference between the two?
The main difference between the size() and capacity() functions in C++ vectors is that size() returns the number of elements currently stored in the vector, while capacity() returns the maximum number of elements that the vector can currently hold without needing to allocate more memory. In other words, size() represents the actual number of elements that have been added to the vector, while capacity() represents the size of the underlying array used by the vector.
Follow-up 2
What happens when you add elements to a vector beyond its current capacity?
When you add elements to a vector beyond its current capacity, the vector needs to allocate more memory to accommodate the new elements. This process is called reallocation. The vector will allocate a new, larger array, copy the existing elements to the new array, add the new elements, and deallocate the old array. This reallocation process can be expensive in terms of time and memory, especially if the vector needs to be resized frequently.
Follow-up 3
How does resizing affect the vector's capacity?
When you resize a vector in C++, the vector's capacity may change depending on the new size. If the new size is less than or equal to the current capacity, the capacity remains unchanged. However, if the new size is greater than the current capacity, the vector needs to allocate more memory to accommodate the new size. The new capacity will typically be larger than the new size to allow for future growth without frequent reallocation. Resizing a vector can be an expensive operation if it requires reallocation, so it is generally more efficient to reserve enough capacity in advance if you know the maximum number of elements the vector will hold.
Live mock interview
Mock interview: Arrays and Vectors in C++
- Read your scene and goals
- Talk it out; goals tick off live
- Get a score and stronger lines
Your voice and your AI key never touch our servers; the key stays in this browser and is sent only to Google. Only your round scores are saved to track progress.