C Mastery / Arrays Part 1: Declaration, Initialization, Decay
Part 1 — The Core Language

Arrays Part 1: Declaration, Initialization, Decay

This chapter introduces arrays, their initialization, and the single most important — and most misunderstood — behavior in C: array-to-pointer decay.

Why This Matters

Arrays are the fundamental contiguous storage in C. Decay is the rule that makes arrays and pointers seem interchangeable when they are not. Understanding decay — and its exceptions — prevents a whole class of sizeof, parameter, and return-value bugs.

Prerequisites

Core Concept

Arrays are contiguous objects

An array is a contiguous sequence of objects of the same type. Its size is fixed at declaration (for non-VLA arrays) and is part of its type.

int arr[5];   /* five consecutive int objects */

arr[0] through arr[4] are the elements. sizeof(arr) is 5 * sizeof(int).

Array-to-pointer decay

In most contexts, an expression of array type is converted ("decays") to a pointer to its first element. The result is int * pointing to arr[0], not a pointer to the array.

int arr[5];
int *p = arr;     /* arr decays to &arr[0] */

This is why arrays and pointers often appear interchangeable in function arguments and loops.

Syntax

Declaration and initialization

int a[5];                    /* uninitialized (automatic) or zeroed (static) */
int b[5] = {1, 2, 3};        /* remaining elements are 0 */
int c[] = {1, 2, 3, 4, 5};   /* size inferred: 5 */
int d[5] = {0};              /* all elements 0 */

Designated initializers (C99)

int e[5] = { [2] = 7, [4] = 9 };   /* e[2]=7, e[4]=9, others 0 */

Indexing

arr[i]       /* element i (0-based) */
*(arr + i)   /* equivalent, by definition */

Array subscripting is defined in terms of pointer arithmetic: arr[i] is *((arr) + (i)).

Examples

sizeof vs. decay

#include <stdio.h>

int main(void)
{
    int arr[10];
    printf("%zu\n", sizeof(arr));        /* 40 (10 * 4) */
    printf("%zu\n", sizeof(&arr[0]));    /* 8 (pointer size) */
    return 0;
}

Expected output (typical LP64): 40 then 8.

Array as a function parameter decays

#include <stdio.h>

void print_size(int a[10])   /* parameter is really int *a */
{
    printf("%zu\n", sizeof(a));   /* size of a POINTER, not the array */
}

int main(void)
{
    int arr[10];
    print_size(arr);
    return 0;
}

Expected output: 8 (pointer size), not 40.

The exceptions to decay

Decay does not happen when the array is:

1. the operand of sizeof; 2. the operand of & (address-of) — &arr is int (*)[10], a pointer to the whole array; 3. a string literal used to initialize a character array.

int arr[10];
sizeof(arr);      /* whole array */
&arr;             /* int (*)[10] */

How It Works

At the type level, arr has type int[10]. In an expression where a value is needed, the compiler converts it to &arr[0] (type int *). The original array object still exists and has its full size; only the *expression* changes type. This is why sizeof (which does not evaluate its operand and which looks at the *type*, not the value) sees the full array.

Variations

Arrays of any type

Arrays can hold any object type, including structs, pointers, and other arrays (multidimensional arrays, c.core.22).

String literals

A string literal "abc" is an array of char with static storage. It decays to char * in expressions, but you must not modify it (it is typically in read-only memory, and modifying it is UB).

Common Mistakes

dead array).

int *).

Undefined Behavior

VERIFIED

VERIFIED

Portability

decay rules themselves.

Under the Hood

An array is a contiguous block of memory. Decay is a compile-time type change that produces an address; it generates no code. Indexing compiles to address arithmetic with a scaled offset.

Practical Usage

pointer alone carries no length.

pointer.

Exercises

1. Write a program that prints sizeof of a local array, a pointer to it, and an array parameter, and explain the differences. 2. Initialize an array with designated initializers and print it. 3. Demonstrate that arr[i] == *(arr + i) by printing both. 4. Explain why &arr + 1 differs from arr + 1 (type and value).

Deep Challenge

Write a function that accepts a pointer to a whole array (int (*a)[10]) and prints sizeof(*a), then contrast it with a function that accepts int *a. Explain the exact type difference and when you would use the pointer-to-array form.

References

conversion), §6.5.3.4 (sizeof), §6.7.9 (initialization).

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.arr.decl05
c.arr.decay06