The Array Abstraction
In C, an Array is a collection of elements of the same type, stored in a contiguous block of memory. This physical contiguity is what makes arrays extremely fast: calculating the address of an element at index i is a simple arithmetic operation.
Array Decay and Pointers
One of the most confusing aspects of C is the relationship between arrays and pointers. In most expressions, an array name decays into a pointer to its first element.
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr; // 'arr' decays to &arr[0]
Because of this, the bracket notation arr[i] is actually syntactic sugar for pointer arithmetic:
arr[i] is identical to *(arr + i).
Lack of Bounds Checking
C is a “trust the programmer” language. It does not check if an index is within the bounds of an array at runtime.
- Accessing
arr[10]on an array of size 5 will simply read whatever happens to be in memory at that offset. - This results in Undefined Behavior (UB) and is a primary source of security vulnerabilities (Buffer Overflows).
Square Bracket Syntax
int vals[5] = {1, 2, 3};
// Which expression is equivalent to vals[2]?
// Answer: Multi-dimensional Arrays
C stores multi-dimensional arrays in Row-Major Order. This means the elements of the first row are stored first, followed by the second row, and so on.
int matrix[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
In memory, this looks like a single flat sequence: 1, 2, 3, 4, 5, 6.
Array Parameters in Functions
When you pass an array to a function, you are actually passing a pointer to the first element. The function has no way of knowing the size of the array unless you pass it as a separate argument.
Interactive Lab
Waiting for signal...
Designated Initializers (C99)
Modern C allows you to initialize specific elements of an array by their index, which is incredibly useful for sparse arrays or configuration tables:
int settings[100] = { [0] = 1, [50] = 5, [99] = -1 };
In this example, all other elements are automatically initialized to zero.