Arrays are contiguous
An array is a block of identical-sized elements packed together in memory, one after another,
no gaps. int arr[4] is 16 contiguous bytes: element 0 at offset 0,
element 1 at offset 4, element 2 at offset 8, element 3 at offset 12.
This is what makes indexing fast — there's no searching. The CPU calculates the address
of any element in one multiply-and-add: base + index × sizeof(element).
arr[2] means "go to the address of arr,
move forward by 2 element-widths, read what's there."
Array decay
In most expressions, an array name decays to a pointer to its first element. This is automatic. You don't write it — it just happens.
The pointer arithmetic rule
When you add an integer to a pointer, the compiler scales by the element size automatically.
Adding 1 to an int* advances the address by 4 bytes, not 1.
arr[10] on a 4-element array compiles without error and reads
whatever bytes happen to be 40 bytes past the start of arr.
That's a buffer overread — and a security vulnerability.
Passing arrays to functions
You can't actually pass an array to a function. The array decays to a pointer. The function receives the pointer and knows nothing about the original array's size. You must pass the length separately.
See it in memory
The visualization below shows an array laid out byte by byte in memory. Switch to the "Array indexing" tab to click each element and see the address arithmetic.
arr[i] is syntax sugar for *(arr + i). Arrays and pointers are the same arithmetic.