Arrays: Memory Visualized

See how arrays actually work under the hood. Add elements, watch memory shift, and understand why arrays are O(1) for access.

Interactive Memory Diagram

Click a cell to select it. Use controls below to add/remove elements and watch memory shift.

Click a cell to see its memory address calculation

Address Calculation

base_address + (index * element_size)
Select an element to see the math

Why Contiguous Memory Matters

An array stores all elements in a single, unbroken block of memory. Each element sits immediately after the previous one, with no gaps. This is what makes arrays special:

O(1) Random Access

Because elements are evenly spaced, the CPU can calculate any element's address with one formula: base + index * size. No searching needed.

Cache-Friendly

When you read arr[0], the CPU loads nearby memory into cache. Since arr[1], arr[2]... are right next door, they're already cached.

O(n) Insertion

To insert in the middle, every element after the insertion point must shift right. More elements = more shifting = slower.

Fixed Size Trade-off

Arrays can't grow without allocating a new, larger block and copying everything. Dynamic arrays (ArrayList/list) hide this but it still happens.

Code Examples

// Declare and initialize
int[] arr = {10, 20, 30, 40, 50};

// Access element — O(1)
int val = arr[2]; // 30

// Modify element — O(1)
arr[0] = 99;

// Iterate through array
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}

// Two pointers pattern
int left = 0, right = arr.length - 1;
while (left < right) {
    // process arr[left] and arr[right]
    left++;
    right--;
}

// Dynamic array (resizable)
ArrayList<Integer> list = new ArrayList<>();
list.add(10);  // O(1) amortized
list.add(1, 99); // O(n) — shifts elements
# Python lists are dynamic arrays under the hood
arr = [10, 20, 30, 40, 50]

# Access element — O(1)
val = arr[2]  # 30

# Modify element — O(1)
arr[0] = 99

# Iterate through array
for num in arr:
    print(num)

# Two pointers pattern
left, right = 0, len(arr) - 1
while left < right:
    # process arr[left] and arr[right]
    left += 1
    right -= 1

# Append — O(1) amortized
arr.append(60)

# Insert at index — O(n), shifts elements
arr.insert(1, 99)

# Slicing (creates new array)
sub = arr[1:4]  # [99, 20, 30]

Time Complexity

Operation Time Why
Access by index O(1) Direct address calculation
Set by index O(1) Same calculation, then write
Search (unsorted) O(n) Must check each element
Search (sorted) O(log n) Binary search halves each step
Insert at index O(n) Shift all elements after index
Delete at index O(n) Shift all elements after index
Append (end) O(1)* Amortized; occasional resize is O(n)

Built on Arrays

Arrays are the foundation for nearly every other data structure:

Stacks

Array with a top pointer. Push/pop from the end in O(1).

Queues

Circular array with head/tail pointers. Enqueue/dequeue in O(1).

Hash Maps

Array of buckets. Hash function maps keys to array indices.

Heaps

Complete binary tree stored in an array. Parent at i, children at 2i+1 and 2i+2.

Want more CS fundamentals explained visually?

Follow @dannygardnercode on Instagram for weekly deep dives into data structures, algorithms, and interview prep.