Be careful with pointer arguments : Do not try to allocate memory or change address

Start from an example below:

#include <iostream>
using namespace std;

struct ListNode {
    int val;
    ListNode * next;
    ListNode(int x) : val(x), next(NULL){}
};

void foo(ListNode * a, ListNode * b){
    a = b;
}

int main(int argc, char *argv[]){
    ListNode * head = new ListNode(0);
    ListNode * headcp = NULL;
    foo(headcp, head);
    cout<<headcp->val<<endl;
    return 0;
}

The intuition is: I want to use function foo(T* a, T* b) to let a save a copy of pointer b.

Unfortunately, the above code will give a runtime error since after the function call, the variable headcp is still a null pointer. The root reason is that, the arguments of function are saved in the memory block called stack frame. In the function body, only the copies of the parameters are changed, but not the parameters passed to the function.

One solution is passing a reference of the pointer I want to change to the function:

#include <iostream>
using namespace std;

struct ListNode {
    int val;
    ListNode * next;
    ListNode(int x) : val(x), next(NULL){}
};

void bar(ListNode *& a, ListNode * b){
    a = b;
}

int main(int argc, char *argv[]){
    ListNode * head = new ListNode(0);
    ListNode * headcp = NULL;
    bar(headcp, head);
    cout<<headcp->val<<endl;
    return 0;
}

Then, the output will be 0.

In articles [1] and [2], authors discussed this point in detail. The author [2] points out the risk of memory leak when trying to allocate memory to a pointer argument in the function:

void GetMemory(char *p, int num){
    p = (char *)malloc(sizeof(char) * num);
}
int main(){
    char *str = NULL;
    GetMemory(str, 100); 
    strcpy(str, "hello");
    return 0;
}

Therefore, the solution is passing a pointer of a pointer to the function or passing a reference of a pointer to the function:

void GetMemory(char **p, int num){
    //the allocation is made directly on the value pointed by *p
    *p = (char *)malloc(sizeof(char) * num);
}
int main(){
    char *str = NULL;
    GetMemory(&str, 100); // pass the address of pointer str
    strcpy(str, "hello");
    free(str);  // do not forget to free memory
    return 0;
}

Or,

void GetMemory(char * &p, int num){ // *& order matters
    //the allocation is made directly at the address of *p
    p = (char *)malloc(sizeof(char) * num);
}
int main(){
    char *str = NULL;
    GetMemory(str, 100); 
    strcpy(str, "hello");
    free(str); 
    return 0;
}

References:

  1. 指针作为函数参数传递
  2. 高质量C++/C编程指南

Yang Song

Ph.D. Student in Robotics