Arrays
A row of boxes, all the same type, accessed by index — and what happens when you walk off the end
So far we've worked with one variable at a time. But many problems involve lots of values of the same kind: a list of scores, a sequence of temperatures, a row of pixels. C's most basic answer is the array: a contiguous block of memory holding many values of the same type.
Declaring and indexing
int scores[5]; // 5 ints, indices 0..4, values undefined
int primes[5] = {2, 3, 5, 7, 11}; // declared and initializedEach individual cell is accessed by index, starting from zero:
primes[0] // 2
primes[1] // 3
primes[4] // 11If you don't supply a size, the compiler counts the initializers:
int primes[] = {2, 3, 5, 7, 11}; // size becomes 5 automaticallyMemory layout: an array is a row of boxes
Address: 0x100 0x104 0x108 0x10c 0x110
Index: [0] [1] [2] [3] [4]
Value: 2 3 5 7 11Each int is (say) 4 bytes. The five cells sit next to each
other in memory. primes[i] is shorthand for "the cell at address
primes + i * sizeof(int)". This contiguity is the secret to why
arrays are fast: predicting the next address is one addition.
The size is fixed at declaration
In C, the size of a standard array is set when it's declared and cannot grow:
int data[10]; // exactly 10 ints, foreverIf you need a list that resizes, you need to manage memory
yourself with malloc and realloc — the topic of the dynamic
memory chapter.
Walking an array with a loop
The natural way to process every element:
Two new tricks above:
sizeof(data) / sizeof(data[0])computes the number of elements at compile time. (It works only on a real array, not on a pointer — more on that subtlety in the pointers chapter.)(double)sum / ncasts so we get a real average, not an integer one.
Initialization shortcuts
int zeros[100] = {0}; // first element is 0; the rest are zero-filled
int arr[5]; // uninitialized! contents are garbage.
int chars[8] = {[2] = 'a', [4] = 'b'}; // designated initializers (C99)The first form is a common idiom: any partial initializer list zero-fills the remaining elements.
Off-by-one and bounds
C does not check array indices. If you write primes[10] and the
array only has five elements, the compiler will not stop you and the
program may:
- Crash (if it reads past the end of allocated memory).
- Silently return garbage from neighboring memory.
- Corrupt a different variable that happened to be next door.
This is called a buffer overflow, and it has been responsible for an astonishing fraction of all software security flaws since the 1980s.
The first three lines are sensible; the last two are garbage (and could be different each run). The rule is simple but iron:
Always check that your index
isatisfies0 <= i < Nbefore usinga[i].
Common patterns
Find the maximum
Reverse in place
Visualize one swap:
Count occurrences
Multi-dimensional arrays
You can have arrays of arrays:
grid[3][4] is laid out as 12 consecutive integers in row-major
order — row 0, then row 1, then row 2. Knowing the layout helps you
reason about cache performance and pointer arithmetic later.
Passing arrays to functions
When you pass an array to a function, you actually pass a pointer to its first element. The function has no automatic way to know the length. You must pass it explicitly:
Inside sum, sizeof(a) would return the size of a pointer (8 on a
64-bit system), not the size of the original array. The
information is genuinely lost at the call site. This is the most
notorious "gotcha" in C, and the reason every C function that takes
an array also takes a length.
Challenge: count odds and evens
The array data holds {7, 2, 9, 4, 9, 6, 1, 8}. Compute how many of its elements are odd and how many are even, and print exactly:
odd = 4
even = 4
What is the value of a[2] after this code runs?
int a[5] = {10, 20, 30, 40, 50};
a[2] = a[0] + a[4];
30
50
60
100
Why is the following code dangerous?
int data[10];
for (int i = 0; i <= 10; i++) {
data[i] = i * i;
}
It doesn't compile.
It runs an infinite loop.
It writes one element past the end of the array (data[10]), which is undefined behavior and may corrupt other memory.
It runs correctly because C will resize the array.