Q:

Why does this unsafe code throw a NullReferenceException?

I was playing with unsafe code for a problem on Code Golf, and I found something I can't explain. This code:
unsafe
{
    int i = *(int*)0;
}

Crashes with an access violation (Segfault), but this code:
unsafe
{
    *(int*)0=0;
}

Throws a NullReferenceException. It appears to me that the first is performing a read and the second is performing a write. An exception tells me that something, somewhere in the CLR is intercepting the write and stopping it before the OS kills the process. Why does this happen on the write, but not on the read? It does segfault on a write if I make the pointer value sufficiently large. Does that mean there is a block of memory that the CLR knows is reserved and will not even attempt to write to? Why then, does it allow me to try and read from that block? Am I completely misunderstanding something here?
Edit:
Interestingly enough: System.Runtime.InteropServices.Marshal.WriteInt32(IntPtr.Zero, 0); Gives me an access violation, not a NullReference.

A:

The first exception makes sense, of course - you're trying to read from memory address 0. The second one's a little more interesting. :P In C++, there is a macro/constant called NULL which has a value of 0. It is used for pointer addresses that are invalid - much like the null value in C# for reference types. Since C# references are pointers internally, a NullReferenceException occurs when you try to read/write from that address - the address NULL or 0; in fact, the addresses from 0 to 64K are invalid in all processes (in Windows) so as to catch programer mistakes. The exact exception or error may vary slightly by computer hardware or version of Windows/.NET Framework, but you should get an error with both code snippets.
As for the segfault when reading/writing to random addresses, that is due to the OS's isolation of each process. You can't fiddle around with other processes' code or data - at least not legitimately.

