Can a null pointer be re-used?
Yes
if yes, under what conditions?
Always
Your question is actually equivalent to ask when it's ok to reuse an int that has been set to zero, or any other value for that matter. What you need to know is that you cannot undo an assignment, so whatever value the pointer contains will be lost. This is the only direct consequence of reassigning a pointer, null or not null. Any problems will be a consequence of no longer having access the previous value. The reassignment itself is always fine, provided it's done properly. See below.
There are basically two common problems related to this when it comes to pointers.
Dangling pointers. This will happen after you call free on a pointer. It will also happen if the object the pointer is pointing at goes out of scope. A dangling pointer contains garbage, and it's undefined behavior to dereference it.
Memory leaks. If you have allocated memory with malloc or similar to a pointer p and then reassign the pointer, you may lose the ability to free the allocated memory.
But it is always legal to reassign a pointer. What value it contains does not affect that. Consider this code:
...
int *p;
...
p = x;
If this is ok or not will entirely depend on x. Both it's type and value and if it is initialized or not.
More specifically, can anyone tell what happens with this piece of code?
It does work. But I have a few remarks.
It's not necessary to initialize the pointer to null before assigning. Some say it's a good habit. Others say it's bad. There are pros and cons and depends on the situation. I personally think it's bad1 to always2 use it.
1 In short, my argument is that if null initialization solves a problem, then you might have a much bigger problem in your design that the initialization will not solve, but only hide.
2 There are valid use cases. Use it in those cases, but make sure you understand why you're doing it.
There's no need to cast the result from malloc. Again, some say it's good. Some say it's bad. I think it's bad, unless you want to compile the C code with a C++ compiler.
Don't use sizeof(int). Use sizeof *p instead.
See Do I cast the result of malloc? to read about 2 and 3.
I'd write your code as
int *p = malloc(sizeof *p);
if(!p) {
// Handle error
}