The decision as to what happens when using what address is rather complex. It depends on the processor architecture, OS and sometimes “what some software does”.
The processor may not have memory protection, or address zero may indeed be “used for something” (in x86 real-mode, that DOS runs in, address zero contains the vector table, where interrupts and such jump to, so it’s incredibly sensitive to being overwritten – hence badly written programs could and would crash not just themselves but the entire machine in DOS).
Typically, modern OS’s on processors that have “virtual memory mapping” (so the physical address that the processor actually uses is not (or may not be) the same as the virtual address that the program sees) will map address zero as “not accessible” for your typical applications.
The OS may allow access to address zero at times:
I had a bug in a Windows driver many years ago, that used a NULL-pointer, and that that particular situation, address 0 was not causing a crash. The crash happened much later when the content of address zero was being used for something – at which point the system blue-screened (at least until I attached the debugger and debugged the problem, and then fixed it so it didn’t try to use a NULL pointer – I don’t remember if I had to allocate some memory or just skipped that bit if the pointer was NULL).
The choice of 0 for NULL is based on a combination of “we have to choose some value (and there is not one value that can be 100% sure that nobody will ever need to use)” – particularly on machines with a 16 or 32-bit address range. Normally, however, address zero, if it is used, contains something “special” (vector table for interrupts, bootstrap code for the processor, or similar), so you are unlikely to meaningfully store data in there. C and C++ as languages do not require that NULL-pointers can’t be accessed [but also does not “allow you” to freely access this location], just that this value can be used as “pointer that doesn’t point at anything” – and the spec also provides for the case where your NULL value is not ACTUALLY zero. But the compiler has to deal with “ZERO means NULL for pointers, so replace it with X”.
The value zero does, at least sometimes, have a benefit over other values – mostly that many processors have special instructions to compare with or identify zero.
1
solved Why location 0x00000000 is accessible if it is a flash memory