Variables Are Memory Addresses
Why should you care?
You write:
int age = 20;
It looks like age is simply a box containing the number 20.
But what actually happens in memory?
Where is 20 stored?
How does the computer find it?
And what exactly happens when you write:
age = 21;
Understanding the relationship between variables, memory locations, and addresses is one of the most important steps toward understanding pointers, references, stack memory, heap memory, and low-level programming.
There is one important correction to the title:
A variable is not literally a memory address. A variable is a programming-language abstraction associated with a value and, when applicable, a storage location. That location can have a memory address, but the compiler may also keep the value in a CPU register or optimize the variable away entirely.
The Problem
Consider this C program:
#include <stdio.h>
int main() {
int age = 20;
printf("%d\n", age);
return 0;
}
When you write:
int age = 20;
you are telling the compiler that you want a variable called age containing an integer value.
Conceptually, memory might look like:
Memory
┌───────────────┐
│ Address │
├───────────────┤
│ 0x7FFE1000 │ → 20
└───────────────┘
The address is where the data can be located.
The variable name age is how your source code refers to that value.
So we have:
Variable
↓
Storage location
↓
Value
But the exact implementation is decided by the compiler and runtime.
The Concept
A memory address identifies a location in an address space.
Imagine memory as a huge collection of numbered locations:
Address Value
0x1000 → 42
0x1004 → 17
0x1008 → 99
0x100C → 5
The numbers on the left are addresses.
The numbers on the right are stored values.
When a program needs data, the processor ultimately needs to access the relevant storage location.
For example:
age = 20
might conceptually correspond to:
Address
0x1000
↓
Value
20
The address tells the computer where.
The value tells it what.
Simple Explanation
Think of your house.
Your address tells someone where your house is.
Your name identifies who lives there.
Your belongings are the actual things stored inside.
Similarly:
Variable name → age
Memory address → 0x1000
Stored value → 20
These are three different concepts.
age
↓
"the integer variable I'm referring to"
0x1000
↓
"where the storage is located"
20
↓
"the value currently stored there"
This distinction becomes extremely important when learning pointers.
Real-world Analogy
Imagine a library.
Every shelf has a location:
Shelf A12
Shelf B27
Shelf C42
A book has a title:
"Operating Systems"
And the book contains information.
So:
Book name → Operating Systems
Location → Shelf B27
Content → Book's pages
Similarly:
Variable name → age
Memory address → 0x1000
Value → 20
The variable name is a convenient way for the programmer to refer to stored data.
Code Example
C allows us to see the address of a variable using the & operator.
#include <stdio.h>
int main() {
int age = 20;
printf("Value: %d\n", age);
printf("Address: %p\n", (void*)&age);
return 0;
}
You might get output similar to:
Value: 20
Address: 0x7ffd23a4
The exact address will vary between executions.
Now look at the difference:
age
means:
Give me the value of age.
While:
&age
means:
Give me the address of age.
So:
age → value
&age → address
This is the foundation of pointers.
Pointers
A pointer is a variable that stores an address.
For example:
#include <stdio.h>
int main() {
int age = 20;
int *ptr = &age;
printf("Value: %d\n", age);
printf("Address: %p\n", (void*)&age);
printf("Pointer contains: %p\n", (void*)ptr);
return 0;
}
Conceptually:
age
┌──────────────┐
│ 20 │
└──────────────┘
↑
│
│ address
│
ptr
┌──────────────┐
│ 0x7FFD... │
└──────────────┘
The pointer doesn't contain 20.
It contains the address of the memory location where 20 is stored.
Dereferencing
Now we can use the pointer to access the value.
int age = 20;
int *ptr = &age;
printf("%d\n", *ptr);
Output:
20
The * operator here means:
Go to the address stored in ptr
and retrieve the value there.
So:
ptr
↓
Address
↓
Memory
↓
20
This operation is called dereferencing.
Changing a Value Through a Pointer
You can also modify the value through its address.
int age = 20;
int *ptr = &age;
*ptr = 21;
printf("%d\n", age);
Output:
21
What happened?
age
↓
Memory location
↓
20
*ptr = 21
age
↓
Memory location
↓
21
The pointer allowed us to access the same storage location indirectly.
Common Mistakes
Mistake 1: Thinking a variable is an address
This is the biggest misconception.
A variable is a language-level abstraction.
It may correspond to a memory location, but it does not necessarily have a permanent physical address.
For example, a compiler may keep:
int x = 10;
inside a CPU register.
In that case, there may be no RAM location associated with x during some part of execution.
Mistake 2: Confusing & and *
In C:
&x
means:
Address of x
while:
*x
when x is a pointer, means:
Value at the address stored in x
Remember:
& → address of
* → dereference
Mistake 3: Thinking addresses never change
A variable's storage location can change during execution depending on the language, runtime, compiler, stack behavior, and memory management.
Modern operating systems also use virtual memory, meaning the address visible to a process is generally a virtual address, not a direct physical RAM address.
Mistake 4: Assuming every variable is stored in RAM
Not necessarily.
A compiler can optimize a variable into:
- CPU registers
- Memory
- Another optimized representation
- No storage at all
For example:
int x = 10;
int y = x + 5;
The compiler may determine that storing x in memory is unnecessary.
Advanced Notes
Virtual Addresses
The address you see in a program is generally a virtual address.
For example:
0x7FFE1234
does not necessarily mean that physical RAM location 0x7FFE1234 contains the data.
Instead:
Virtual Address
↓
Memory Management Unit
↓
Physical Memory
The operating system and hardware manage this translation.
This is one of the reasons processes can have isolated address spaces.
Stack Variables
Consider:
void function() {
int x = 10;
}
x has automatic storage duration and is commonly associated with the function's stack frame.
Conceptually:
Stack
┌──────────────┐
│ Local data │
├──────────────┤
│ x = 10 │
├──────────────┤
│ Return info │
└──────────────┘
The exact implementation can differ because compilers may optimize local variables into registers or eliminate them.
Heap Variables
Dynamically allocated memory is commonly associated with the heap.
For example:
int *ptr = malloc(sizeof(int));
*ptr = 50;
Conceptually:
ptr
↓
Address
↓
Heap
┌──────────────┐
│ 50 │
└──────────────┘
Here, ptr stores an address pointing to dynamically allocated storage.
What About Java?
Java makes this concept slightly different.
Consider:
int age = 20;
You cannot directly obtain the raw memory address of age using normal Java language features.
Java intentionally hides direct memory manipulation from ordinary application code.
For objects:
Person person = new Person();
person is better understood as a reference to an object, not as a C-style pointer that programmers can freely perform arithmetic on.
This abstraction provides safety and allows the JVM and garbage collector to manage memory.
So the relationship is:
C
Variable → Memory location → Address
Java
Variable → Value or Reference → Object
The JVM decides how and where objects are actually represented.
The Bigger Picture
This concept connects several important areas of computer science.
Variables
↓
Memory
↓
Addresses
↓
Pointers / References
↓
Stack & Heap
↓
Virtual Memory
↓
Operating System
↓
CPU
Once you understand this chain, concepts such as:
- Pointers
- References
- Arrays
- Function calls
- Stack frames
- Dynamic memory
- Garbage collection
- Virtual memory
become much easier to understand.
Summary
A variable is not literally a memory address.
Instead, think of three separate concepts:
Variable
↓
Storage
↓
Value
When storage has an address, we can think of:
Variable → Address → Value
For example:
age
↓
0x7FFE1000
↓
20
In C:
age
accesses the value.
&age
gets its address.
And:
*ptr
dereferences an address stored in a pointer.
The deeper lesson is that programming languages give us abstractions over the physical machine. Sometimes a variable corresponds to memory, sometimes it lives in a register, and sometimes the compiler eliminates it completely.
Understanding that distinction is the first step toward thinking like a systems programmer.
Top comments (0)