But a itself is not pointing to another region of memory, it IS the region of memory itself. So when the compiler converts it to a pointer, does it save it (like p) somewhere in memory or it's an implicit conversion?
Logically speaking, it's an implicit conversion - there's no requirement that the implementation materialize permanent storage for the pointer.
In terms of implementation, it's up to the compiler. For example, here's a simplistic bit of code that creates an array and prints its address:
#include <stdio.h>
int main( void )
{
int arr[] = { 1, 2, 3 };
printf( "%p", (void *) arr );
return 0;
}
When I use gcc to compile it for x86-64 on a Red Hat system, I get the following machine code:
GAS LISTING /tmp/ccKF3mdz.s page 1
1 .file "arr.c"
2 .text
3 .section .rodata
4 .LC0:
5 0000 257000 .string "%p"
6 .text
7 .globl main
9 main:
10 .LFB0:
11 .cfi_startproc
12 0000 55 pushq %rbp
13 .cfi_def_cfa_offset 16
14 .cfi_offset 6, -16
15 0001 4889E5 movq %rsp, %rbp
16 .cfi_def_cfa_register 6
17 0004 4883EC10 subq $16, %rsp
18 0008 C745F401 movl $1, -12(%rbp)
18 000000
19 000f C745F802 movl $2, -8(%rbp)
19 000000
20 0016 C745FC03 movl $3, -4(%rbp)
20 000000
21 001d 488D45F4 leaq -12(%rbp), %rax
22 0021 4889C6 movq %rax, %rsi
23 0024 BF000000 movl $.LC0, %edi
23 00
24 0029 B8000000 movl $0, %eax
24 00
25 002e E8000000 call printf
25 00
26 0033 B8000000 movl $0, %eax
26 00
27 0038 C9 leave
28 .cfi_def_cfa 7, 8
29 0039 C3 ret
30 .cfi_endproc
31 .LFE0:
33 .ident "GCC: (GNU) 7.3.1 20180712 (Red Hat 7.3.1-6)"
34 .section .note.GNU-stack,"",@progbits
Line 17 allocates space for the array by subtracting 16 from the stack pointer (yes, there are only 3 elements in the array, which should only require 12 bytes - I'll let someone with more familiarity with the x86_64 architecture explain why, 'cause I'll get it wrong).
Lines 18, 19, and 20 initialize the contents of the array. Note that there's no arr variable in the machine code - it's all done in terms of an offset from the current frame pointer.
Line 21 is where the conversion occurs - we load the effective address of the first element of the array (which is the address stored in the %rbp register minus 12) into the %rax register. That value (along with the address of the format string) then gets passed to printf. Note that the results of this conversion aren't stored anywhere other than the register, so it will be lost the next time something writes to %rax - IOW, no permanent storage has been set aside for it the same way storage has been set aside for the array contents.
Again, that's how gcc in Red Hat running on x86-64 does it. A different compiler on a different architecture will do it differently.