In many C implementations (but not all), NULL corresponds to a process's logical address 0.
No, that is the wrong way to look at it. Null pointers do not correspond to anything other than themselves, by definition, and C in no way ties null pointers to any particular address, in any sense of the term.
At best, you could say that some implementations' representations of null pointers have the form that a representation of a pointer to an object residing at machine address 0 would have. Since null pointers compare unequal to every pointer to an object or function, however, such a situation requires that it be impossible for any object or function that the C program can reference to reside at that address.
When we try to dereference NULL, we get a segmentation fault
That is one of the multitude of observed behaviors that are possible when you invoke undefined behavior. Empirically, it is one of the more likely to be observed when undefined behavior is invoked in the particular way you describe. It is by no means guaranteed by C, and indeed, there are widely-used implementations which, empirically, exhibit different behavior.
because NULL "maps" to a memory segment that is neither readable nor writable.
But there you're delving deep into implementation details.
Is there a real, physical address that corresponds to the virtual NULL address?
No, because a null pointer is not an address. It is a pointer value that is explicitly invalid to dereference. Technically, although C refers to some pointer values as "addresses", it neither requires nor depends on any pointer value to be a machine address, neither a physical nor a virtual one. The value of a null pointer, however, is not an address even in C's sense of the term. The &
operator never produces this value, and it is invalid to dereference -- it explicitly fails to correspond to any object or function.
If so, what might be stored there? Or is NULL purely a virtual address with no physical counterpart?
Although it is indeed common for null pointer values to be represented in the way that a pointer to an object / function residing at machine address 0
would be, this is irrelevant, because in that case a C program can never access anything residing at that address. Thus, as far as the program is concerned, nothing resides there. As far as the hardware and OS kernel are concerned, on the other hand, external programs' view of memory is largely irrelevant. And if one nevertheless insists on considering the kernel's view of what is stored in physical memory at an address derived from an external program's null pointer representation, it is highly system-dependent.