the page table
The page table is the building manager's private directory: for each tenant (each process) it records, page by page, which physical frame that page currently sits in, or that it has no home yet. It is the data structure that makes address translation possible — the lookup table from virtual page number to physical frame number.
In the simplest picture, a page table is one big array indexed by virtual page number, where each slot is a page-table entry holding a frame number plus some flag bits (present, writable, executable, and so on). To translate, the hardware uses the virtual page number as an index into this array, reads the entry, and gets the frame. Each process has its own page table, which is what makes address spaces private: the OS swaps in the right table when it switches to a process, so the very same virtual address now points to that process's data. A special CPU register (cr3 on x86-64) holds the physical address of the current process's top-level table.
There is a scale problem, though, which is why real page tables are not one flat array. A 64-bit address space is astronomically large; a single flat table covering it would need more memory than exists. The fix is a multi-level page table — a tree that only materialises the branches you actually use — covered next. The key idea to carry forward is that the page table is per-process, lives in physical memory, and is read by the hardware on a TLB miss.
Process A's page table maps virtual page 0x10 to frame 0x3c2; process B's table maps its own virtual page 0x10 to frame 0x88f. Both processes can use address 0x10000 and get their own data, because the OS switches the active page table (via cr3) on every context switch.
Per-process tables are why the same virtual address means different things.
The page table lives in physical RAM and is managed by the OS, not by your program — you never read or write it directly from C. Switching processes means switching page tables, which is part of why a context switch is not free.