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.

  1. Size: C-style arrays have a fixed size determined at compile time. Vectors (std::vector) are dynamic — they grow and shrink at runtime automatically.

  2. 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.

  3. Type safety and bounds checking: C-style arrays decay to pointers, losing size information. In debug builds, vector::at() throws std::out_of_range on invalid access; operator[] has no such check. std::array (fixed-size, stack-allocated) solves the decay problem for fixed sizes.

  4. 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.

  5. Modern alternative — std::span (C++20): When you need to pass an array or vector to a function without copying, prefer std::span. It is a non-owning view over any contiguous sequence (raw array, std::array, or std::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
  1. Performance: For small, fixed-size collections, std::array matches raw-array performance with zero overhead and full STL compatibility. std::vector has a slight overhead from the heap allocation but is generally negligible and preferred for runtime-sized collections.

When to use each:

  • Use std::vector when size is unknown at compile time or may change.
  • Use std::array as a safer, STL-compatible replacement for fixed-size C-style arrays.
  • Use std::span to accept any contiguous range in function parameters.
  • Avoid raw C-style arrays in new code unless interfacing with a C API.
↑ Back to top

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:

  1. 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.

  2. Vectors: Vectors are allocated on the heap. The memory for a vector is allocated at runtime using dynamic memory allocation (usually new or malloc). The size of the vector can be changed dynamically using the resize() method. The memory for the vector must be deallocated manually using the delete or free function 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:

  1. 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.

  2. 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.

  3. Safety: Vectors handle memory allocation and deallocation automatically, reducing the risk of memory leaks and buffer overflows compared to arrays.

  4. 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 &lt;&lt; x &lt;&lt; ' ';
}

In new code, prefer std::array over C-style arrays for fixed sizes, and std::vector when the size is dynamic.

↑ Back to top

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 to push_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; throws std::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() — returns true if size is zero.

Iteration

  • Range-based for: for (auto&amp; 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.

↑ Back to top

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 &lt;&lt; myVector[0] &lt;&lt; std::endl; // Output: 10
    std::cout &lt;&lt; myVector.at(1) &lt;&lt; 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 &lt;&lt; num &lt;&lt; " ";
    }
    // 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 &lt;&lt; num &lt;&lt; " ";
    }
    // 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&gt;;

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&gt; 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] or std::array,M&gt; — fixed compile-time dimensions, stack allocated.
  • std::vector&gt; — fully dynamic but non-contiguous.
  • Flattened std::vector with manual indexing — dynamic and cache-friendly.
  • std::mdspan (C++23) — non-owning multidimensional view over any contiguous storage; the preferred modern approach when available.
↑ Back to top

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() &lt;= 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 &lt;&lt; v.size();      // 3
std::cout &lt;&lt; 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 &gt;= 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.

↑ Back to top

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++

Intermediate ~5 min Your own free AI key

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.

Next lesson Linked List, Queue, and Stack in C++ →