📦 Section 2 · Arrays & Pointers 🟡 Intermediate MODULE 08

Pointers — The Core of C++

⏱️ 35 min read
📖 Theory + Code
🧩 5 Quiz Questions
🏗️ 1 Challenge
Your progress in Section 260%
🎯 What you'll learn: What a memory address actually is, the & and * operators, how to declare and use a pointer, how arrays and pointers relate, pointer arithmetic, nullptr, and why pointers are the single most important idea separating C++ from languages like Python or JavaScript.

What Is a Memory Address?

Every variable in your program lives somewhere in your computer's memory (RAM). That "somewhere" is a numeric address — think of your computer's memory as one enormous street of numbered mailboxes, and every variable you declare gets assigned to one of those mailboxes.

In Python or JavaScript, this address is completely hidden from you. In C++, you can see it, hold onto it, and pass it around — and that ability is the foundation of everything in this lesson.

address_of.cpp — Seeing a Memory Address
C++
// address_of.cpp
#include <iostream>
using namespace std;

int main() {
    int age = 25;
    cout << "Value of age: " << age << endl;
    cout << "Address of age: " << &age << endl;

    return 0;
}

Running this prints something like Address of age: 0x7ffee2a3b4ac — a hexadecimal number representing where age lives in memory. That exact number will be different every time you run the program, and that's expected.

The Address-Of Operator &

Placing & directly before a variable name gives you that variable's address instead of its value. You just saw this with &age above. This is the first of the two operators you must master to understand pointers.

💡
& means "address of"
Read &age out loud as "the address of age." It doesn't change age at all — it just tells you where age lives in memory.

Pointer Declaration & The Dereference Operator *

A pointer is a variable whose job is to store a memory address — usually the address of another variable. You declare one by writing the type it points to, an asterisk *, and a name.

pointer_basics.cpp — Declare, Point, Dereference
C++
// pointer_basics.cpp
#include <iostream>
using namespace std;

int main() {
    int age = 25;
    int* agePtr = &age;   // agePtr now holds the address of age

    cout << "Value of age: " << age << endl;
    cout << "Address stored in agePtr: " << agePtr << endl;
    cout << "Value pointed to by agePtr: " << *agePtr << endl;

    *agePtr = 30;   // change age THROUGH the pointer
    cout << "New value of age: " << age << endl;

    return 0;
}

Notice that * is used in two different ways here — in the declaration int* agePtr, it means "this variable is a pointer to an int." In an expression like *agePtr, it means "dereference — give me the value stored at the address this pointer holds." Same symbol, different meaning depending on context.

⚠️
Dereferencing through the pointer changes the original variable
After *agePtr = 30;, age itself becomes 30 — because agePtr and age refer to the exact same memory location. This is fundamentally different from copying a value.

The 3-Step Mental Model

Every time you work with a pointer, you're really doing three distinct steps. Internalize this pattern and pointers stop feeling mysterious.

1
Declare a pointer
int* p; — p is a variable that will hold the memory address of an int. Right now it doesn't point anywhere safe yet.
2
Point it at a variable
p = &age; — now p stores the address of age. p and age are connected.
3
Dereference it
*p — reads or writes the value living at that address. Reading gives you age's value; assigning to *p changes age itself.

Pointers and Arrays

Back in Lesson 6 you learned that arrays "decay" into pointers when used in most expressions. Here's what that actually means: an array's name, on its own, evaluates to the address of its first element. That's why you can assign an array directly to a pointer.

array_decay.cpp — Arrays & Pointer Arithmetic
C++
// array_decay.cpp
#include <iostream>
using namespace std;

int main() {
    int nums[4] = {10, 20, 30, 40};
    int* p = nums;   // array decays to a pointer at its first element

    for (int i = 0; i < 4; i++) {
        cout << "nums[" << i << "] = " << *(p + i) << endl;
    }

    p++;   // moves forward by sizeof(int), not by 1 byte
    cout << "After p++, *p = " << *p << endl;

    return 0;
}

The expression *(p + i) is exactly equivalent to nums[i] — in fact, that's literally how the compiler implements array indexing under the hood. Square-bracket indexing is really just pointer arithmetic wearing a friendlier syntax.

Pointer Arithmetic

When you add 1 to a pointer, C++ doesn't move it forward by 1 byte — it moves it forward by the size of the type it points to. An int* advances by sizeof(int) bytes (commonly 4), a double* advances by sizeof(double) bytes (commonly 8), and so on. This is exactly why p++ in the example above correctly landed on nums[1] instead of some random byte in the middle of an int.

This is what makes p + i work for indexing
Because the compiler already knows the size of the pointed-to type, p + i automatically calculates the correct byte offset to land exactly on element i — you never have to compute byte offsets yourself.

Null Pointers (nullptr)

A pointer that isn't pointing at anything valid yet should be set to nullptr — a special value meaning "this pointer intentionally points to nothing." Checking for nullptr before dereferencing a pointer is a habit that prevents an entire category of crashes.

nullptr_check.cpp — Checking Before Dereferencing
C++
// nullptr_check.cpp
#include <iostream>
using namespace std;

int main() {
    int* ptr = nullptr;   // ptr points to nothing (yet)

    if (ptr == nullptr) {
        cout << "ptr is not pointing to anything" << endl;
    }

    int value = 99;
    ptr = &value;   // now it's safe to dereference

    if (ptr != nullptr) {
        cout << "*ptr = " << *ptr << endl;
    }

    return 0;
}
⚠️
Dereferencing a nullptr crashes your program
Writing *ptr while ptr is nullptr is one of the most common C++ crashes, called a null pointer dereference. Always initialize pointers to nullptr when you don't yet have a valid address for them, and check before dereferencing if there's any doubt.

Why Pointers Matter

It's fair to ask: why does C++ make you deal with all this, when Python and JavaScript hide it completely? Here's the payoff.

pass_by_pointer.cpp — Modifying Without Copying
C++
// pass_by_pointer.cpp
#include <iostream>
using namespace std;

void doubleValue(int* n) {
    *n = *n * 2;
}

int main() {
    int x = 21;
    doubleValue(&x);
    cout << "x is now: " << x << endl;

    return 0;
}
Efficiency
Passing a pointer (an address) is cheap, even for enormous data — copying the whole thing every time a function is called is not.
🔧
Modify Without Copying
A function can change the original variable directly through a pointer, as doubleValue() just did to x.
🏗️
Dynamic Data Structures
Linked lists, trees, and graphs — covered later in this course — are built entirely out of pointers connecting pieces of data together.
🧠
Foundation of the Rest of C++
Dynamic memory (Lesson 9), classes, and even STL iterators all work the way they do because of pointers underneath.

Lesson Summary

Let's recap everything you learned in this lesson:

Every variable lives at a memory address; & gives you that address.
A pointer is a variable that stores an address; * dereferences it to reach the value.
The mental model is always: declare → point → dereference.
An array's name decays to a pointer to its first element — *(p + i) equals arr[i].
Pointer arithmetic moves by the pointed-to type's size, not by raw bytes.
Initialize unused pointers to nullptr, and never dereference one that might be null.
🧩 Knowledge Check — Lesson 8
Answer all 5 questions to test your understanding. Instant feedback on every answer.
1. What does & do when placed directly before a variable name?
2. What does * do when placed before a pointer variable in an expression (dereferencing)?
3. Given int* p = &age;, what does p actually store?
4. If p is an int*, what happens when you write p++?
5. What does a pointer initialized to nullptr point to?
💪
Coding Challenge — Lesson 8
Apply what you learned · Intermediate Level

Now it's your turn to write real code. Complete the challenge below in your own C++ environment.

Challenge: Swap Two Integers with Pointers 🔀

Write a C++ program called swap.cpp containing a function void swapValues(int* a, int* b) that swaps the values of two integers using pointers only — no return value, no third array. Call it from main() on two variables and print their values before and after the swap.

Rules: Use a temporary variable inside the function to hold one value during the swap. Pass the addresses of your two variables using & when calling the function. Confirm the swap actually worked by printing both variables after the call.
💡 Show hints if you're stuck
  • Inside the function: int temp = *a; *a = *b; *b = temp;
  • Call it like swapValues(&x, &y); from main()
  • Because you passed addresses, the changes inside the function affect the original x and y
  • Print x and y both before and after the call to see the difference
Finished this lesson?
Mark it complete to track your progress.
🎉

Lesson 8 Complete!

You've just learned the concept that defines C++. Next: putting pointers to work with dynamic memory allocation.

Module 08 of 26 Section 2 — Arrays, Strings & Pointers