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):
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
intrequiresint *; modifying anint *requiresint **. - Traces
out_buf(the stack address ofmain's pointer),*out_buf(main's pointer variable itself), and**out_buf(the firstintinside the allocated buffer). - Shows how
struct Node **can walk a linked list by pointing at theheadpointer first and then at each node's.nextpointer (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_bufbefore checkingif (out_buf != NULL)when designing public C APIs. - Confusing a
char **array of pointers (argv) with a contiguous 2Dchar[R][C]array.