I think since we are not accessing NULL memory, we will get the address
of "b", even if "a" is NULL.
Please quote enough context so that people know what you are
referring to.
Your reply is with respect to a->b where a is NULL.
a->b is the same as (*a).b by definition. b must therefore be
a field name within the structure type associated with *a.
As b is a field name and not a variable, b has no address of its
own, so your analysis cannot be correct.
In considering (*a).b with a being NULL, you should understand
that the C standards say that doing this is not allowed and that
the results are undefined. The standards do not say that the program
must crash: crashing is one of the allowed options, as is doing
something else completely like accessing an I/O register or loading
a random number. Crashing is relatively easy to track down; the
other possibilities might lurk undetected for decades.
One of the allowed behaviours for (*a).b with a being NULL, is to
calculate the distance of the field b relative to the begining
of the structure, and then attempt to access a memory location that
much further along from whatever bit pattern NULL happens to be,
which often -happens- to be the all-zero bit pattern. For example,
if the field b happens to start 84 bytes from the beginning of the
structure then the code might try accessing location 0+84 . And
that just might happen to work, because there just might happen to
be valid and accessible memory at that location. Or it might happen
to crash if the system knows there is no memory there. Or it might
happen to return 0's, if the memory system knows there is no memory
there and automatically substitutes 0's. I've seen all of these
behaviours on real systems.
There is no problem here too. I am yet to get a satisfactory answer.
This is slightly different in that the address of (*0).field is
being taken without the content of (*0).field being needed.
This does not need to go to the memory hardware for lookup, so
*some* systems would treat the above as calculating the offset of
the field relative to the beginning of the structure. It doesn't
really calculate that, though, as it is the wrong type (address
instead of offset).
According to the C standards, the -> operator is only valid when
its left side is a pointer to an object, and 0 (or NULL) are
defined as pointing to NO object. Therefore the code
does not have a defined result according to the C standards.
It isn't uncommon to see the code in the implementation of
offset(), but that's because the implementation is allowed to take
advantage of internal knowledge of the operating system, and so
is allowed to do things that C programmers cannot safely do in
user programs. The code is *not* portable. (But as I discussed
above, systems are not -required- to give an error when they
encounter it.)