본문으로 건너뛰기
Previous
Next
C++ Pointers Explained: Understand “Hard” Pointers in 5

C++ Pointers Explained: Understand “Hard” Pointers in 5

C++ Pointers Explained: Understand “Hard” Pointers in 5

이 글의 핵심

Learn C++ pointers using a simple address analogy: core ideas, hands-on examples with code, patterns you will see in practice, and mistakes to avoid.

Think of pointers as street addresses

Analogy: A pointer is like a street address.

variable = house (where the data actually lives)
pointer  = address (information that says where the house is)

Core concepts

Variables and addresses

int age = 25;        // variable: stores a value
int* ptr = &age;     // pointer: stores an address

// &age: take the address of age
// ptr: a pointer that stores age's address

Picture it:

Address     Name   Value
0x1000      age    25
0x2000      ptr    0x1000 (address of age)

Declaring pointers

Example C/C++ code:

int* ptr;      // pointer to int
double* ptr2;  // pointer to double
char* ptr3;    // pointer to char

// Asterisk placement is style-only:
int *ptr;      // same meaning
int * ptr;     // same meaning

Address-of operator (&)

Example C/C++ code:

int x = 10;
int* ptr = &x;  // store x's address in ptr

std::cout << x;     // 10 (value)
std::cout << &x;    // 0x7fff.... (address)
std::cout << ptr;   // 0x7fff.... (address, same as &x)

Dereference operator (*)

Example C/C++ code:

int x = 10;
int* ptr = &x;

std::cout << *ptr;  // 10 (value ptr points to)

*ptr = 20;          // change the value where ptr points
std::cout << x;     // 20 (x changed!)

Hands-on examples

Example 1: swapping values (swap)

Implementation sketch for swap_wrong vs swap:

// Wrong: copies values only
void swap_wrong(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    // When the function returns, a and b are back to the originals!
}

// Correct: use pointers
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 10, y = 20;

    swap_wrong(x, y);
    std::cout << x << ", " << y;  // 10, 20 (unchanged)

    swap(&x, &y);
    std::cout << x << ", " << y;  // 20, 10 (swapped!)
}

Example 2: arrays and pointers

Example C/C++ code:

int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr;  // array name is the address of the first element

std::cout << *ptr;       // 1 (first element)
std::cout << *(ptr+1);   // 2 (second element)
std::cout << ptr[2];     // 3 (third element)

Common mistakes

Mistake 1: uninitialized pointer

Example C/C++ code:

// Dangerous
int* ptr;
*ptr = 10;  // we don't know where this points! (crash)

// Correct
int* ptr = nullptr;  // points to nothing
// or
int x;
int* ptr = &x;  // points to x

Mistake 2: confusing pointer and value

Example C/C++ code:

int x = 10;
int* ptr = &x;

// Wrong
ptr = 20;  // compile error! (assigning a value to an address slot)

// Correct
*ptr = 20;  // change the value ptr points to

Mistake 3: dangling pointer

Example C/C++ code:

// Dangerous
int* ptr;
{
    int x = 10;
    ptr = &x;
}  // x is gone
*ptr = 20;  // use-after-free of a dead variable! (crash)

// Better: dynamic allocation
int* ptr = new int(10);
*ptr = 20;
delete ptr;  // release when done

Pointers vs references

Example C/C++ code:

// Pointer
int x = 10;
int* ptr = &x;
*ptr = 20;  // must dereference

// Reference (often simpler)
int& ref = x;
ref = 20;   // no dereference

Tip: Beginners often learn references first.

Dynamic memory allocation

new and delete

Example C/C++ code:

// Single object
int* ptr = new int;      // allocate
*ptr = 10;               // store value
delete ptr;              // free

// With initial value
int* ptr2 = new int(25);
delete ptr2;

// Array
int* arr = new int[100];  // array of 100 ints
arr[0] = 1;
delete[] arr;             // array delete ([] required!)

Watch for memory leaks

Example leak vs no_leak:

// Leak
void leak() {
    int* ptr = new int(10);
    // forgot delete!
}  // ptr goes away but the memory stays allocated

// Correct
void no_leak() {
    int* ptr = new int(10);
    // ... use ...
    delete ptr;  // always pair with new
}

Everyday analogy: Think of memory as an apartment building. The stack is like a fast elevator—quick but limited space. The heap is like a warehouse—roomy but takes longer to “fetch” from. A pointer is a sticky note that says “3rd floor, unit 302”—it records an address, not the furniture inside.

Pointer arithmetic

Example C/C++ code:

int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr;

std::cout << *ptr;       // 10
std::cout << *(ptr+1);   // 20
std::cout << *(ptr+2);   // 30

// Increment the pointer
ptr++;
std::cout << *ptr;       // 20

// Array-style indexing
ptr[0];  // 20
ptr[1];  // 30

Why we use pointers

1. Changing values inside a function

Example increment:

void increment(int* num) {
    (*num)++;
}

int main() {
    int x = 10;
    increment(&x);
    std::cout << x;  // 11 (changed)
}

2. Passing large data efficiently

Example process:

// Inefficient: copies the whole vector
void process(std::vector<int> data) {
    // ...
}

// Efficient: pass pointer
void process(std::vector<int>* data) {
    // ...
}

// Often better: const reference
void process(const std::vector<int>& data) {  // recommended
    // ...
}

3. Arrays whose size is unknown at compile time

Example C/C++ code:

int n;
std::cin >> n;

// Size not known at compile time
int* arr = new int[n];  // size decided at runtime
// ... use ...
delete[] arr;

FAQ

Q1: Why do people say pointers are hard?

A: The idea is simple, but small mistakes often crash the program.

Why it feels hard:

  • Uninitialized pointer → crash
  • Missing delete → leak
  • Double delete → crash
  • Use-after-free → crash

Mitigation: use smart pointers in modern C++:

#include <memory>

std::unique_ptr<int> ptr = std::make_unique<int>(10);
// delete happens automatically (safer)

Q2: What is nullptr?

A: A special value meaning “points to nothing.”

int* ptr = nullptr;  // points to nothing

if (ptr == nullptr) {
    std::cout << "Pointer is empty" << std::endl;
}

// Check before use (safe)
if (ptr != nullptr) {
    *ptr = 10;
}

Note: Prefer nullptr (C++11) over the old NULL macro.

Q3: How do pointers relate to arrays?

A: An array name is the address of its first element.

Example C/C++ code:

int arr[5] = {1, 2, 3, 4, 5};

// Array name = address of first element
int* ptr = arr;  // same as &arr[0]

// Equivalent forms
arr[2];      // 3
ptr[2];      // 3
*(arr+2);    // 3
*(ptr+2);    // 3

Q4: What is a double pointer?

A: A pointer that points to another pointer.

Example C/C++ code:

int x = 10;
int* ptr = &x;       // address of x
int** ptr2 = &ptr;   // address of ptr

std::cout << x;      // 10
std::cout << *ptr;   // 10
std::cout << **ptr2; // 10

// ptr2 → ptr → x

When it shows up:

  • Dynamic 2D arrays
  • Functions that must change a pointer value
  • Advanced structures (trees, graphs)

Q5: Can I learn C++ without raw pointers?

A: In modern C++, largely yes.

Instead of raw new/delete:

Example C/C++ code:

// Old style
int* ptr = new int(10);
delete ptr;

// Modern: smart pointer
auto ptr = std::make_unique<int>(10);
// automatic cleanup

// Reference (often simpler)
int x = 10;
int& ref = x;
ref = 20;

Suggested order:

  1. References
  2. Smart pointers
  3. Raw pointers when you actually need them

Q6: When must I still use raw pointers?

A: Typical cases:

Often required:

  • C libraries (OpenGL, SDL, etc.)
  • Systems programming
  • Embedded development
  • Maintaining legacy code

Often avoidable:

  • Typical apps: references and smart pointers
  • Games: mostly smart pointers
  • Web servers: references often enough

Takeaway: In modern C++, you need fewer raw owning pointers in application code.


Deep dive: const pointer vs pointer to const (often confused at work)

int x = 1;
const int* p1 = &x;   // pointee is const (can't change *p1 through p1)
int* const p2 = &x;   // pointer itself is const (can't repoint p2)
const int* const p3 = &x; // both const

Reading tip: Many teams read declarations as: const before * → “what is pointed to”, const after * → “the pointer itself.”


Deep dive: void*, alignment, and uintptr_t

When you touch C APIs you will see void*. In C++, cast back to the correct type with static_cast before dereferencing, and use uintptr_t (<cstdint>) when you treat an address as an integer.

std::byte buffer[64];
auto* p = new (buffer) int(42);
// Bad idea: casting arbitrary addresses to int* can break alignment / strict aliasing rules

Performance: A single dereference is usually one or two cycles, but cache misses, virtual calls, and synchronization often dominate. Before blaming “pointers are slow,” look at memory access patterns.


Deep dive: debugging (GDB and sanitizers)

SituationTool
Random crashesAddressSanitizer (-fsanitize=address)
Suspected heap corruptionASan + -fsanitize=undefined (where supported)
LeaksLeakSanitizer (with ASan), Valgrind
“Where did it break?”GDB watch on *ptr, bt
// GDB: when you doubt whether a pointer still points to a valid object
// print ptr
// x/4wx ptr   (memory dump — invalid ptr can segfault)

Deep dive: more risky patterns

PatternWhy it is riskyAlternative
Double deleteUndefined behaviorSet to nullptr after delete, or use smart pointers
Old iterators after vector reallocationInvalidationUse indices or reserve to stabilize ranges
reinterpret_cast abuseStrict aliasing issuesstd::bit_cast (C++20) or redesign
C-style varargs + pointersType mismatchesPrefer modern APIs

Deep dive: mini example — linked list node (educational)

struct Node {
    int value{};
    Node* next{nullptr};
};

void push_front(Node*& head, int v) {
    auto* n = new Node{v, head};
    head = n;
}

void free_list(Node* head) {
    while (head) {
        Node* next = head->next;
        delete head;
        head = next;
    }
}

In production you would usually use std::unique_ptr<Node>. The snippet shows why rules matter when a pointer implies ownership.


Posts that connect to this topic:

  • C++ stack vs heap: recursion crashes, memory layout, RAII and smart pointers
  • C++ observer pointer guide
  • [C++ functions: beginner guide with examples](/en/blog/cpp-function-basics/
  • [C++ classes and objects](/en/blog/cpp-class-object-beginner/

같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.

  • [C++ Memory Management: new/delete, Stack vs Heap, and RAII](/en/blog/cpp-memory-management-deep/
  • [C++ Stack vs Heap](/en/blog/cpp-series-06-1-memory-basics/
  • [C++ Code Review | ](/en/blog/cpp-code-review-checklist/

이 글에서 다루는 키워드 (관련 검색어)

C++, pointers, address, dereference, beginner, tutorial 등으로 검색하시면 이 글이 도움이 됩니다.