Phase 2 · Arrays, Strings & MemoryModule 7~42 min read

Arrays

Store fixed-size sequences, traverse them safely, pass them to functions, and work with multidimensional arrays.

What you'll learn

An array stores a fixed number of same-typed elements in one contiguous region of memory. That simple layout makes arrays fast and foundational—and makes precise bounds essential.

By the end, you'll be able to:

  • Declare, initialize, index, and update arrays
  • Process arrays with safe zero-based loops
  • Pass an array together with its length to a function
  • Work with row-major multidimensional arrays

Declare & initialize arrays

Put the element count inside brackets. Initializers fill elements from left to right; omitted elements become zero. A designated initializer can target a particular index.

arrays.c
#include <stdio.h>

int main(void) {
    int scores[5] = {88, 92, 75, 100, 84};
    int zeros[4] = {0};             // every element becomes zero
    int inferred[] = {3, 6, 9};     // compiler infers length 3
    int sparse[6] = {[1] = 10, [4] = 40};

    scores[2] = 79;
    printf("%d %d %d %d\n",
           scores[2], zeros[3], inferred[2], sparse[4]);
    return 0;
}

Watch out

An uninitialized automatic array contains indeterminate elements. Use an initializer when you expect meaningful starting values.

Contiguous memory

Five int elements in one array
12

[0]

7

[1]

25

[2]

4

[3]

18

[4]

lower addresshigher address

Every element has the same type and sits immediately after the previous element.

If one int occupies four bytes on a platform, a five-element array occupies twenty consecutive bytes. C can find element i by movingi × sizeof(element) bytes from the beginning.

Key idea

Valid indexes for an array of count elements are 0 throughcount - 1. The one-past position is useful for comparison but must never be dereferenced.

Traverse & process

A zero-based for loop naturally visits every element. Common operations include counting, summing, finding an extreme, searching, and transforming values.

array_stats.c
#include <stdio.h>

int main(void) {
    int scores[] = {88, 92, 75, 100, 84};
    size_t count = sizeof scores / sizeof scores[0];
    int total = 0;
    int highest = scores[0];

    for (size_t i = 0; i < count; i++) {
        total += scores[i];
        if (scores[i] > highest) highest = scores[i];
    }

    printf("Average: %.1f\n", (double) total / count);
    printf("Highest: %d\n", highest);
    return 0;
}

Compute element counts

In the scope where an array is actually declared, divide its total byte size by one element's size:

ExpressionMeaning
sizeof scoresTotal bytes occupied by the entire array
sizeof scores[0]Bytes occupied by one element
sizeof scores / sizeof scores[0]Number of elements

This formula is local to real arrays

After an array is passed to a function, its parameter behaves as a pointer. There,sizeof parameter measures the pointer—not the caller's array. Pass the count explicitly.

Arrays and functions

An array argument gives a function access to the original elements. The function needs a separate length because no end marker is carried automatically. Use const when the function only reads.

array_function.c
#include <stddef.h>
#include <stdio.h>

double average(const int values[], size_t count) {
    if (count == 0) return 0.0;

    long total = 0;
    for (size_t i = 0; i < count; i++) {
        total += values[i];
    }
    return (double) total / count;
}

int main(void) {
    int values[] = {4, 8, 15, 16, 23, 42};
    size_t count = sizeof values / sizeof values[0];

    printf("%.2f\n", average(values, count));
    return 0;
}

Note

In a parameter list, const int values[] andconst int *values describe the same parameter type. The bracket form can make array intent easier to read.

Multidimensional arrays

A two-dimensional array is an array whose elements are themselves arrays. C stores rows contiguously in row-major order.

matrix.c
#include <stdio.h>

#define ROWS 2
#define COLS 3

int main(void) {
    int matrix[ROWS][COLS] = {
        {1, 2, 3},
        {4, 5, 6}
    };

    for (size_t row = 0; row < ROWS; row++) {
        for (size_t col = 0; col < COLS; col++) {
            printf("%d ", matrix[row][col]);
        }
        putchar('\n');
    }
    return 0;
}

Tip

Traversing columns inside rows follows the storage order and usually makes good use of the processor cache.

Bounds & safety

C does not insert automatic bounds checks. An invalid index accesses storage that does not belong to that element, producing undefined behavior.

bounds.c
int values[5] = {0};

values[0] = 10;  // valid: first element
values[4] = 50;  // valid: last element

// values[5] = 60;  // BUG: one past the array
// values[-1] = 5;  // BUG: before the array
  • Carry the element count with the array
  • Use size_t for sizes and indexes
  • Write conditions as index < count
  • Test empty, one-element, and full-capacity cases

Recap & quick check

Key takeaways

  • Arrays contain a fixed count of same-typed elements in contiguous memory.
  • An array of count elements has valid indexes from zero through count minus one.
  • The sizeof-array formula works only where the operand is still an array.
  • Array-processing functions should receive the array and its element count.
  • Multidimensional arrays are nested arrays stored in row-major order.

Quick check

1. What is the final valid index of int values[8]?

2. Why pass a count with an array parameter?

3. What does contiguous mean?

4. How does C store a two-dimensional array?

Arrays give C compact sequences. Next up: Module 8 — Strings & Character Handling, where character arrays become text.