Overview of program's perception of memory
- Each program is loaded into an isolated, private address space. It cannot see the memory of another program. The hardware and the OS works together to enforce the address space protection.
- The address space on a 32-bit machine ranges from 0 through 0xffffffff (232 - 1); on a 64-bit machine, it ranges from 0 through 0xffffffffffffffff (264 - 1). A number that represents memory location in the address is called a pointer.
- At address 0, there is a reserved NULL page intentionally made inaccessible in order to catch NULL pointer reference. This is because functions can only return one value, and NULL pointer (which is numeric 0) conventionally indicates an error condition. If a programmer forgets to check for error, the program can dereference NULL pointer and crash. This is the best case scenario so you can debug. It is better than if the program keeps running, reading random garbage from memory. NULL pointer dereference causes segmentation fault (see null.c below).
- The asterisk serves two purposes. In null.c, char *p declares variable p to be a character pointer. In an expression, *p causes the character value at pointer p to be read out, or dereferenced.
- Use the command: objdump -h a.out and you'll find the sections in your executable. The rodata, data, and bss sections store global variables: rodata (read-only) stores string literals (what you write in the program inside double quotes) and other things; data stores initialized read-write variables; bss stores uninitialized global variables (or those initialized to 0). You can observe the change of bss and data section sizes (see section.c below).
- Heap grows upward (not going to be observed for now), but stack grows downward (see stack.c). Local variables are placed on stack, and function call forces the stack to grow, so the char c in main() occupies a higher address than the char c in foo(). &c (unary & operator) gives you the address of the variable c.
Array, pointer arithmetic, and string