No, dereferencing a null pointer doesn't guarantee a crash.
For one thing, in many cases, the compiler is able to optimize out the dereference operation. in your case, &(p->c)
nominally dereferences a null pointer, but you then take the address of the result (after selecting a member of the pointed-to structure). Presumably the compiler replaces the entire expression by a number, which is the offset of the members within the structure. (There's no guarantee that a null pointer refers to address 0, or that it will be optimized in this manner, but it happens to do so on your system.)
This is the basis of a common implementation of the standard offsetof
macro. It can't be implemented in portable standard C or C++, but implementations commonly use system-specific tricks like this -- which is perfectly valid as long as it yields the correct result on that system.
Second, even if you actually dereference a null pointer, the behavior is undefined. This might mean that your program crashes, but as far as the language standard is concerned it can do literally anything.
There have been systems in the past (and there probably still are) where a null pointer refers to address 0, and the system's memory map is set up so that address 0 is a valid memory address that happens to contain a 0 value. On such a machine, for example, a null pointer acts like a pointer to an empty '\0'
-terminated character string. This led to a flurry of bug fixes when code that worked on such systems, and which unintentionally depended on that behavior, was ported to newer systems with stronger memory protection. (I think this may have been the transition from the 68K-based Sun 3 to the SPARC-based Sun 4, but I'm not sure of that.)
For more information on null pointers, see section 5 of the comp.lang.c FAQ. Most of it applies to C++ as well.
printf()
are Undefined Behavior (UB)."%d"
is the wrong matching specifier for a pointer. Use"%p"
. – Reiss