| I have wondered about how this exactly works. My professor told us that you cannot point to memory outside of your application. And that your not really pointing to a memory location, but rather virtual memory addresses in a table that the operating system has provided your application (or something akin to that). He didn't get very specific; left it at "it's complicated", and you'll learn about it in an operating systems class.|
That protection is actually provided by the CPU. When a program tries to access a memory address the CPU (or MMU) checks if it's allowed (according to data provided by the OS). It also translates virtual memory addresses into real memory addresses (according to the same data). If it's not, it generates a segmentation or page fault. Usually the OS then kills the offending process*. That's a simplified version of events, anyway: for details, read about segmentation and paging, those are the mechanisms by which memory protection and virtual memory are implemented on x86 and x86-64 CPUs. In short, for segmentation there's a GDT (Global Descriptor Table) which stores segment selectors and their flags (readable, writeable, executable) as well as the privilege level required to access them. For paging, there's a page table which essentially does the same thing, but the advantage is that the pages don't need to be contiguous. All x86 CPUs, as well as x86-64 CPUs in 32-bit emulation, use segmentation (although those before the 80286 don't have any protection), but some of the later ones (can) also use paging, and x86-64 CPUs don't use segmentation at all when they're in 64-bit mode (they have what's called a "flat memory model" which is infinitely better than a "segmented" one).
* Linux also uses page faults to implement copy-on-write: when a process creates a child process, the two processes initially share memory, which the kernel marks as read-only and shared. That way, it doesn't have to make a copy which saves some time (and memory). If either of the processes tries to write to the memory then the CPU generates a page fault because it's marked as read-only. Linux then makes a copy of the memory (hence copy-on-write) and marks the original and the copy as writeable and non-shared. Of course, that's only if the memory was writeable to begin with; if it was read-only already then it will never be copied and writing to it will just result in the process being killed. Windows doesn't support copy-on-write AFAIK: when you create a new process it just copies the memory immediately, but I'm pretty sure all UNIX-based systems (including OS X) do. I don't know if they implement it the same way, though.