Pointers are passed to the function by value. Essentially, this means that the pointer value (but not the pointee!) is copied. What you modify is only the copy of the original pointer.
There are two solutions, both using an additional layer of indirection:
Either you use a reference:
void f(int*& a) {
a = new int[4];
}
Or you pass in a pointer-to-pointer (less conventional for out parameters as in your case):
void f(int** pa) {
*pa = new int[4];
}
And call the function like this:
f(&a);
Personally, I dislike both styles: parameters are for function input, output should be handled by the return value. So far, I've yet to see a compelling reason to deviate from this rule in C++. So, my advise is: use the following code instead.
int* create_array() {
return new int[4];
}