First, Please see this discussion on why not to cast the return value of malloc() and family in C...
That said, note the line
int *v = p;
here, v was made to point to the same memory address as that of the p. So, any change made to the value at address via pointer v will be reflected while accessing the memory via p and vice-versa.
To present it graphically, let's say , malloc() returned a pointer address 0x8000 which is stored in p, and we have the value 45 stored in the memory address pointed to by p (in the address 0x8000).
Now, by saying int *v = p;, we're making p also to point to 0x8000 memory address. Deferencering either v or p will use the content of the memory 0x8000.
+--------------------------+
| |
| 45 |
| |
+--------------------------+
0x8000
+----------------+ +--+-------------+
| p = 0x8000 | | v = p = 0x8000|
| | | |
+----------------+ +----------------+