Is the address of a variable in C the real address in the RAM of the computer?

Yes and no. When you take the address of a variable, and perform some operations on it (assuming the compiler doesn't optimize it out), it will correspond to an address in ram. However because of virtual memory, the address used in your program is almost certainly not the address of the variable in physical ram. The kernel remaps what virtual addresses (what your program sees) refer to which physical addresses (what the memory sees), so that different processes can be loaded into memory at the same time, yet not be able to access each others' memory. Additionally, your process's memory can be paged out, or written to disk if it has not been used recently and/or something else needs more memory, and reloaded into a completely different address, yet the virtual address will remain the same.

So yes, when you access a pointer, that address corresponds to an address in memory. But that address doesn't correspond to the actual address in ram, and the address it corresponds to can change over time.


The sort answer is "neither".

In general terms, the address of a variable in memory is in the context of a running program's address space.

What differs is how the program's address space is mapped to hardware by the host system.

With modern hardware that has a memory management unit (MMU), and operating systems (or their device drivers) that use the MMU, a program's address space is mapped to physical memory, which may consist of RAM or virtual memory, such as a swap file on a hard drive. The operating system uses the MMU to isolate programs from each other (so two processes cannot access each other's address space) and also uses the MMU to support swapping of data between RAM and swap. The running process cannot generally tell where its data is in physical memory, because the operating system and MMU specifically prevent it from doing so. Over time, the operating system and MMU may migrate memory used a program to different areas of RAM or to swap, but the program cannot detect this, since the operating system and MMU take care of mapping an address in the program (which never changes as far as the program is concerned) to the actual address. This covers most modern versions of windows, unix, and various realtime operating systems. (Those systems also typically provide means of programatically accessing physical memory, but only for programs that are running with higher privileges or for kernel mode drivers).

Older hardware did not have an MMU, so operating systems were not able to give programs separate address spaces. On such systems, the address as seen by a program had a one-to-one correspondence to a location in physical memory.

Somewhere in between was hardware that had separate areas of physical memory (e.g. provided by distinct banks of memory chips). On those systems, with support of special drivers, a host system could implement a partial mapping between addresses in a program's address space, and locations in particular areas of physical memory. This is why some target systems, and compilers that support them, support more than one pointer type (e.g. with names like near, far, and huge) as a compiler extension. In those cases, a pointer could refer to a location in a particular area of memory, and there may be some mapping of values, for each pointer type, from the value of a pointer seen by a program to the actual location within a corresponding area of physical memory.

The C compiler does not become a part of executable program it builds (otherwise, to install any built program, it would be necessary to also install and execute the compiler used to build it, or the program would not run). Typically, a compiler is no longer running when a program is executed (or, at least, a program cannot rely on it being present). A program therefore cannot access addresses within the compiler's address space.

In an interpreted environment (e.g. C code is interpreted by another program - the interpreter) the interpreter acts as an intermediary between the program and the hardware, and handles mapping between a program's address space, the interpreter's address space, and physical memory. C interpreters are relatively rare in practice, compared with toolchains that use compilers and linkers.