Code of the Day
IntermediatePointers

Pointers and arrays

Understand the deep relationship between pointers and arrays in C — how array names decay to pointers, why sizeof behaves differently, and how to write generic array functions.

CIntermediate11 min read
Recommended first
By the end of this lesson you will be able to:
  • Explain array-to-pointer decay and when it happens
  • Describe the difference between an array and a pointer to its first element
  • Write a function that accepts an array via a pointer and a length
  • Use a pointer to traverse a string without an index variable

In C, arrays and pointers are closely related — but they are not the same thing. The relationship causes more confusion than almost any other aspect of the language. This lesson clarifies the distinction and the places where arrays and pointers behave identically.

Array decay

When you use an array in most expressions, it decays to a pointer to its first element. This happens automatically:

int arr[] = {10, 20, 30};
int *p = arr; /* arr decays to &arr[0] */

After this, p and arr (in most expressions) behave identically:

printf("%d\n", arr[1]);  /* 20 */
printf("%d\n", p[1]);    /* 20 -- same thing */
printf("%d\n", *(p + 1)); /* 20 */

When arrays do NOT decay

In two situations, arrays do not decay:

  1. sizeof: sizeof(arr) gives the total size of the array in bytes. sizeof(p) gives the size of the pointer (8 bytes on a 64-bit machine, 4 on 32-bit) — not the array.
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;

printf("sizeof(arr) = %zu\n", sizeof(arr)); /* 20 (5 * 4 bytes) */
printf("sizeof(p)   = %zu\n", sizeof(p));   /* 8 (pointer size) */
  1. &arr: &arr gives the address of the whole array, not the first element. Its type is int (*)[5] (pointer to an array of 5 ints), not int *. &arr[0] and arr (after decay) give the same numeric address but different types.

Arrays in function parameters

When you pass an array to a function, it decays to a pointer. The function receives a pointer, not a copy of the array:

void print_first(int arr[], int n) {
    /* arr here is int *, not an array */
    printf("sizeof inside: %zu\n", sizeof(arr)); /* 8 -- pointer size */
    printf("First: %d\n", arr[0]);
}

Inside the function, sizeof(arr) gives the pointer size, not the array size. This is why you must always pass the length separately. The declaration int arr[] in a function parameter is exactly the same as int *arr — the [] syntax is syntactic sugar.

Writing generic array functions

With a pointer and a length, you can write functions that work on any-size array:

#include <stdio.h>

int sum(const int *arr, int n) {
    int total = 0;
    for (int i = 0; i < n; i++) {
        total += arr[i];
    }
    return total;
}

int find_max(const int *arr, int n) {
    int max = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) { max = arr[i]; }
    }
    return max;
}

int main(void) {
    int a[] = {3, 1, 4, 1, 5, 9, 2, 6};
    int n = sizeof(a) / sizeof(a[0]);

    printf("Sum: %d\n", sum(a, n));      /* 31 */
    printf("Max: %d\n", find_max(a, n)); /* 9  */

    return 0;
}

The const int *arr parameter means "a pointer to constant ints" — the function promises not to modify the values through the pointer. Use const for read-only parameters.

String traversal with pointers

The pointer style is idiomatic for traversing strings:

#include <stdio.h>

size_t my_strlen(const char *s) {
    const char *start = s;
    while (*s != '\0') {
        s++;
    }
    return (size_t)(s - start);
}

int main(void) {
    printf("%zu\n", my_strlen("Hello")); /* 5 */
    return 0;
}

s starts at the first character and advances until it hits '\0'. The distance s - start is the number of characters — the same result as strlen.

Array of pointers

Arrays can hold pointers:

const char *days[] = {
    "Monday", "Tuesday", "Wednesday",
    "Thursday", "Friday", "Saturday", "Sunday"
};

for (int i = 0; i < 7; i++) {
    printf("%s\n", days[i]);
}

days is an array of 7 const char * pointers. Each pointer points to a string literal. This is the standard C way to represent a list of strings.

The array-pointer relationship is foundational. Many C APIs (file handling, system calls, parsing libraries) pass arrays as pointer-plus-length pairs. Internalising that arrays decay to pointers and that arr[i] equals *(arr + i) will make reading C code much easier.

Where to go next

Next: pointers to pointersint **, the argv pattern, and why double pointers are needed for functions that modify pointer variables.

Finished reading? Mark it complete to track your progress.

On this page