Variables & Memory

5 min read

Reading Progress0%
CS Fundamentals Index
Tier 1 -- Foundations
Tier 2 -- Core Concepts
Tier 3 -- Debugging & Tradeoffs
CS Fundamentals Index
Tier 1 -- Foundations
Tier 2 -- Core Concepts
Tier 3 -- Debugging & Tradeoffs

Variables & Memory

1. What Is It?

A is a name bound to a value stored somewhere in memory. When you write x = 10, you're telling the language: reserve space for the number 10 and give me a way to refer to it as x. Without variables, you'd have to re-compute or re-read every value every time you needed it — and you'd have no way to express "the thing I just calculated" in a program.

What goes wrong without a clean mental model: you get surprised when two variables seem to point at the same data, when a value changes "by itself," or when code runs slower than expected because values are being copied instead of referenced. These are memory-behavior bugs, not syntax bugs, and they only make sense once you picture where the data actually lives.

QUICK CHECK

A junior developer notices that after assigning result = computeTotal(), they never call computeTotal() again, yet they use result dozens of times throughout the function. Which core benefit of variables does this pattern demonstrate?

Choose one answer

2. How It Works

When a is introduced, three things happen:

  1. A name enters a (a lookup table the language uses to resolve identifiers).
  2. Memory is allocated somewhere — on the for small fixed-size data, on the for dynamically-sized or longer-lived data.
  3. The name is bound to that memory, either directly (the name is the slot) or indirectly (the name holds a /pointer to the slot).
# Python
x = 10          # x is a name bound to an int object in Python's managed memory
y = x           # y binds to the SAME object; no copy
x = 11          # x now binds to a different int object; y is unchanged
print(y)        # 10

(Small ints like 10 are cached by CPython, so the already exists — but the mental model "the name points at an " is what matters here.)

// Java
int x = 10;     // x is a stack slot holding the int 10 directly (primitive)
int y = x;      // y is a new stack slot; value 10 is COPIED
x = 11;
System.out.println(y);   // 10

String a = "hi";         // a is a stack slot holding a reference to a String object on the heap
String b = a;            // b holds the SAME reference; no String copy
// C++
int x = 10;     // x is a stack slot holding the int 10 directly
int y = x;      // y is a new stack slot; value 10 is COPIED
int& z = x;     // z is a reference — another name for x's slot
z = 99;         // x is now 99

int* p = new int(5);   // p on stack, int on heap; manual lifetime
delete p;              // you must free it
QUICK CHECK

In a backend service written in Python, a developer writes the following code:

config = {'timeout': 30}
cached = config
config['timeout'] = 60
print(cached['timeout'])
What does this print, and why?

Choose one answer

3. What You Actually Need to Know

  • Assignment is not always a copy. In Python and Java (for objects), assignment copies the , not the data. In C++, = copies the value by default — which can be expensive for large objects.
  • "Uninitialized" means different things. In C++, a local int x; holds garbage — reading it is undefined behavior. In Java, local variables must be assigned before use (compiler error); instance fields default to 0/null. In Python, a name that was never assigned raises NameError.
  • controls lifetime (mostly). A declared inside { } in Java/C++ stops existing when that block ends. In Python, function-local names disappear when the function returns. But if something else still references the (not the name), the itself survives.
  • Common error signals:
    • NameError: name 'x' is not defined (Python) — you misspelled a name or used it before assignment.
    • error: use of uninitialized (C++ compilers with warnings on) — declared but never set.
    • NullPointerException (Java) — variable holds a , but the is null.
    • Mysterious value changes across functions — you passed a and the callee mutated the shared .
QUICK CHECK

A Python backend service has a function that receives a list object, appends an item to it, and returns. After the function returns, the caller notices the original list has been modified. What is the most likely explanation for this behavior?

Choose one answer

4. Language Differences

AspectPythonJavaC++
Must declare type?NoYesYes (or auto)
Primitive-vs-reference split?No — everything is an object referenceYes — primitives (int, double) vs. reference typesYes — value types vs. pointers/references
Default memory for "small" dataHeap (boxed int objects)Stack (primitives)Stack
Who frees memory?Garbage collectorGarbage collectorYou do (via delete, smart pointers, or RAII)
Can a name be rebound?Yes, freelyYes (unless final)Yes (unless const); references cannot be rebound

The key divergence: Python has no "" in the C sense — every name is a to an . Java splits the world in two (primitives are values, objects are references). C++ gives you full control and full responsibility.

QUICK CHECK

A backend team is debugging a memory leak in a long-running API server. In Python, they notice that objects are cleaned up automatically without any explicit deallocation code, while a C++ port of the same service requires careful manual cleanup after each request cycle. Which fundamental difference between the two languages explains this behavior?

Choose one answer

5. Tradeoffs & Decisions

  • Value semantics vs. semantics. If two variables should always move in lockstep, you want semantics. If changes to one must not leak to the other, you want value semantics. Python/Java force reference semantics for objects; C++ lets you pick (T, T&, T*, std::shared_ptr<T>).
  • vs. allocation. is fast and auto-freed but fixed in size and tied to . is flexible but slower and needs cleanup. In C++ you decide; in Java/Python the runtime decides for you (objects on heap, primitives/locals on stack).
  • Re-assignment vs. immutability. const (C++), final (Java), and convention-based constants in Python prevent accidental rebinding. Use them when a represents a fixed configuration or when you want the compiler to catch logic bugs.

If you see mysterious shared mutation, it usually means two names reference the same . You'd choose a copy (or an type) when isolation matters more than memory.

QUICK CHECK

You're building a backend service where a configuration object is created once at startup and passed to multiple handler functions. You want the compiler or runtime to prevent any handler from accidentally reassigning the configuration reference. Which approach best achieves this goal in C++ and Java respectively?

Choose one answer

6. Interview Cheat Sheet

  • A is a named binding to a value in memory — the name lives in a , the value lives in a memory region ( or ).
  • Assignment semantics differ by language and type. Python and Java variables copy references; Java primitives and C++ values copy the data itself.
  • Lifetime is -driven for locals, -count- or GC-driven for objects. The name disappears when its scope ends; the disappears when nothing references it (GC languages) or when you free it (C++).
  • In C++, uninitialized locals hold garbage; reading them is undefined behavior. Java forbids it at compile time; Python throws NameError at runtime.

Follow-ups:

  • "What happens when you do b = a in Python?" — Both names bind to the same object; no copy.
  • "Where do Java primitives live?" — On the (for locals) or inline in the enclosing object (for fields), not as separate heap objects.
  • "Why would you prefer a over a copy?" — Avoid duplicating large data and keep a single source of truth; cost is shared mutation risk.
Glossary History

Click dotted jargon to save explanations here.

Glossary History

Click dotted jargon to save explanations here.