Which brings us to our next point. The address space that you are dealing with is that of the process under examination, not your own. It is impossible to map that process's address space on a one-to-one basis into your own (because of the potential for virtual address conflicts), so you must use lseek(), read() and write() to access this memory.
Why is it impossible to map it on a one-to-one basis? Because the whole point of virtual addressing is that multiple processes could have their own, independent address spaces. It would defeat the purpose of virtual addressing if, once a process was assigned a certain address range, that address range then became unavailable for all other processes.
Since the reason for mapping the address space of the other process to your own would be to use the other process's pointers natively, and since that's not possible due to address conflicts, we'll just stick with the file operations.
Now, in order to be able to read relevant portions of the process's address space, we're going to need to know where these address ranges actually are. There are a number of devctl()'s that are used in this case (we'll see these shortly).