Dataslope logoDataslope

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 initialized

Each individual cell is accessed by index, starting from zero:

primes[0]   // 2
primes[1]   // 3
primes[4]   // 11
Code Block
C 17 (201710L)

If you don't supply a size, the compiler counts the initializers:

int primes[] = {2, 3, 5, 7, 11};   // size becomes 5 automatically

Memory 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      11

Each 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, forever

If 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:

Code Block
C 17 (201710L)

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 / n casts 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.

Code Block
C 17 (201710L)

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 i satisfies 0 <= i < N before using a[i].

Common patterns

Find the maximum

Code Block
C 17 (201710L)

Reverse in place

Code Block
C 17 (201710L)

Visualize one swap:

Count occurrences

Code Block
C 17 (201710L)

Multi-dimensional arrays

You can have arrays of arrays:

Code Block
C 17 (201710L)

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:

Code Block
C 17 (201710L)

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

Challenge
C 17 (201710L)
Count odd and even numbers in an array

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
QuestionSelect one

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

QuestionSelect one

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.

On this page