Tutorials Logic, IN +91 8092939553 info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Interview Questions Website Development
Compiler Tutorials

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

FeatureC-style Arraystd::arraystd::vector
SizeFixed (compile-time)Fixed (compile-time)Dynamic (runtime)
Bounds checkingNo — undefined behaviourYes via at()Yes via at()
STL algorithmsPartial (pointer decay)FullFull
Memory locationStackStackHeap
Knows its own sizeNoYes (.size())Yes (.size())
Prefer in modern C++Only for C interopFixed-size collectionsMost 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.

C-style Array — Declaration, Access, Traversal
#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.

Passing Arrays to Functions
#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).

Sort and Search
#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.

std::array — Complete Guide
#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.

std::vector — Complete Guide
#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.

STL Algorithms — sort, find, count, accumulate, rotate
#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

MethodDescriptionComplexity
push_back(val)Add element to endO(1) amortized
emplace_back(args)Construct element in-place at endO(1) amortized
pop_back()Remove last elementO(1)
insert(pos, val)Insert at iterator positionO(n)
erase(pos)Remove element at iterator positionO(n)
at(i)Access with bounds check (throws)O(1)
operator[](i)Access without bounds checkO(1)
front() / back()First / last elementO(1)
size()Number of elementsO(1)
capacity()Allocated storageO(1)
reserve(n)Pre-allocate for n elementsO(n)
resize(n)Change size (add/remove elements)O(n)
clear()Remove all elementsO(n)
empty()Check if size == 0O(1)
begin() / end()Iterators to first / past-lastO(1)

When to Use Which?

SituationUseReason
Size known at compile time, no overheadstd::arrayStack allocated, zero overhead, safe
Size unknown or changes at runtimestd::vectorDynamic, grows automatically
Interfacing with C APIsC-style array or v.data()C APIs expect raw pointers
Frequent insert/delete in middlestd::list or std::dequeO(1) insert vs O(n) for vector
Default choicestd::vectorMost flexible, best cache performance

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.