Frontend Labs
⋯

11. Pointers to pointers, function pointers, pointers to arrays

11.1 Pointers to pointers: modifying a pointer through a function

#include <stdio.h>
#include <stdlib.h>

int allocate(int **out, int value) {
    *out = malloc(sizeof(int));   // to change the CALLER's pointer, you need its address
    if (!*out) return 0;
    **out = value;
    return 1;
}

int main(void) {
    int *p = NULL;
    if (!allocate(&p, 42)) { perror("malloc"); return 1; }
    printf("%d\n", *p);
    free(p);
    return 0;
}

This is also exactly how argv works: int main(int argc, char *argv[]) — argv is char **, an array of pointers to char (strings), because main needs a variable number of variable-length strings, which is precisely what a pointer-to-pointer expresses.

11.2 Function pointers: C's mechanism for callbacks and polymorphism

#include <stdio.h>
#include <stdlib.h>

int compare_asc(const void *a, const void *b) {
    int ia = *(const int *)a, ib = *(const int *)b;
    return (ia > ib) - (ia < ib);
}
int compare_desc(const void *a, const void *b) {
    int ia = *(const int *)a, ib = *(const int *)b;
    return (ib > ia) - (ib < ia);
}

int main(void) {
    int nums[] = {5, 2, 8, 1, 9};
    int n = sizeof(nums) / sizeof(nums[0]);

    int (*cmp)(const void *, const void *) = compare_asc;  // a variable holding a function
    qsort(nums, (size_t)n, sizeof(int), cmp);

    for (int i = 0; i < n; i++) printf("%d ", nums[i]);
    printf("\n");

    qsort(nums, (size_t)n, sizeof(int), compare_desc);
    for (int i = 0; i < n; i++) printf("%d ", nums[i]);
    printf("\n");
    return 0;
}

qsort's comparator argument is the same mechanism used for every callback-driven C API you'll meet in Part VI — curl's CURLOPT_WRITEFUNCTION, Redis's command dispatch table, and every event loop's "call this function when X happens."

A typedef makes function-pointer types readable:

typedef int (*Comparator)(const void *, const void *);

void sort_ints(int *arr, size_t n, Comparator cmp) {
    qsort(arr, n, sizeof(int), cmp);
}

11.3 Pointers to arrays vs. arrays of pointers — the syntax that trips everyone up

int  (*p1)[5];   // p1 is a pointer to an array of 5 ints
int  *p2[5];     // p2 is an array of 5 pointers to int

int matrix[3][4];
int (*row)[4] = matrix;      // row points to a whole 4-int row; row+1 skips 4 ints

Read declarations from the variable name outward, following precedence: [] and () bind tighter than *, so int *p2[5] groups as int *(p2[5]) — an array, of pointers.


Generated from real-life-c-guide.md · 8 Oct 2026 16:36