TRT
Sign in
easyFoundationscoding

Why does a function need a double pointer (T **) to allocate a buffer or replace the head of a linked list on behalf of its caller?

Trace how passing T * by value only modifies the callee's local pointer copy, whereas passing T ** (&ptr) lets the callee dereference *out_ptr to update the caller's pointer.

TRT practice prompt — not a verified question from a named employer.

The Runtime Theory Team2 min read
Learn it firstPointers to Pointers and IndirectionMaster multi-level pointer indirection, modify caller pointer addresses across function frames, and work with pointer tables.

A strong answer

In C, all function arguments—including pointers—are passed by value. Suppose main has int *buf = NULL; and calls alloc_buffer(buf, 100). If alloc_buffer is declared as void alloc_buffer(int *p, size_t n), the parameter p is a local copy of buf (holding NULL). When alloc_buffer runs p = malloc(n * sizeof(int));, it overwrites its own local variable p on its stack frame. As soon as alloc_buffer returns, p is destroyed, main's buf is still NULL, and the allocated heap block is leaked!

To let a function modify a caller's variable of type X, the caller must pass &var of type X *. When the variable you want to modify is already a pointer (X is int * or struct Node *), its address &buf has type int ** (a pointer to a pointer):

c
int alloc_buffer(int **out_buf, size_t n) {
    int *mem = malloc(n * sizeof(int));
    if (mem == NULL) return -1;
    *out_buf = mem;  /* writes the new address directly into caller's buf! */
    return 0;
}

The exact same rule applies to prepending or deleting the head of a singly linked list (void push_front(struct Node **head_ref, int val)): because inserting at the front changes which node head points to in the caller, the function either must return the new struct Node * head or accept struct Node **head_ref and assign *head_ref = new_node;.

What the interviewer is listening for

  • Applies the universal pass-by-value rule consistently: modifying an int requires int *; modifying an int * requires int **.
  • Traces out_buf (the stack address of main's pointer), *out_buf (main's pointer variable itself), and **out_buf (the first int inside the allocated buffer).
  • Shows how struct Node ** can walk a linked list by pointing at the head pointer first and then at each node's .next pointer (indirect = &(*indirect)->next), removing branches for head insertion/deletion.

Common mistakes

  • Writing out_buf = malloc(...) instead of *out_buf = malloc(...) inside the helper function, which still only modifies the local parameter.
  • Dereferencing *out_buf before checking if (out_buf != NULL) when designing public C APIs.
  • Confusing a char ** array of pointers (argv) with a contiguous 2D char[R][C] array.

This answer walks

Practice follow-ups

  1. 01How can you rewrite linked-list node deletion using a double pointer Node **indirect to eliminate the special case for deleting the head node?
  2. 02Why is main's second parameter declared as char **argv (or char *argv[])?

Not started

Sign in to save your learning progress.

Sign in to save