Compilation unit 1:
Code:
#include <stdio.h>
#include <stdlib.h>

// tell this compilation unit about the existence of function f2
// in another comp. unit
void f2();

int n = 42;    // extern global variable defined in this comp. unit

void f1(int p1) {
    static int x = 123;
    int b = 99;
    if (p1 == 0)
        printf("  f1:   x: %p (%d)\n", (void*)&x, x);
    else {
        printf("  f1:  p1: %p (%d)\n", (void*)&p1, p1);
        printf("  f1:   b: %p (%d)\n", (void*)&b, b);
    }
}

int main() {
    int a = 9;

    printf("text segment:\n");
    printf("  main: %p\n", (void*)main);
    printf("  f1:   %p\n", (void*)f1);
    printf("  f2:   %p\n", (void*)f2);

    printf("data segment:\n");
    printf("  main: n: %p (%d)\n", (void*)&n, n);
    f1(0);
    f2(0);

    int *p = malloc(sizeof *p);
    *p = 9999;

    printf("stack:\n");
    printf("  main: a: %p (%d)\n", (void*)&a, a);
    // pointer itself is stored on the stack;
    // it's value is the heap address that malloc returned
    printf("  main: p: %p (%p)\n", (void*)&p, (void*)p);
    f1(1);
    f2(2);

    printf("heap:\n");
    printf("  main: p: %p (%d)\n", (void*)p, *p);

    free(p);

    return 0;
}
Compilation unit 2:
Code:
#include <stdio.h>

// tell this compilation unit about the existence
// of global variable n in another comp. unit
extern int n;

void f2(int p2) {
    int c = 999;
    if (p2 == 0)
        printf("  f2:   n: %p (%d)\n", (void*)&n, n);
    else {
        printf("  f2:  p2: %p (%d)\n", (void*)&p2, p2);
        printf("  f2:   c: %p (%d)\n", (void*)&c, c);
    }
}