SrcForge

Lesson 20

Pointers

Covers pointer declaration, initialization, dereferencing, null pointers, pointer arithmetic, and pointer to pointer.

Lesson content

What are pointers in C++?

A pointer is a variable that stores the memory address of another variable instead of storing the actual value.

int number = 25;

int* ptr = &number;

The pointer ptr stores the memory address where number is located.

Why do pointers exist?

  • Access memory directly
  • Share data efficiently between functions
  • Allocate memory dynamically
  • Build complex data structures
  • Avoid unnecessary copying of large objects

Real-world use cases

  • Dynamic memory allocation
  • Linked lists
  • Trees and graphs
  • Game development
  • Operating systems
  • Device drivers
  • Database engines
  • Smart pointers and resource management (RAII)

Memory address

Every variable is stored at a unique location in memory. The address-of operator (&) returns the memory address of a variable.

int number = 100;

cout << &number;

// Output (varies each run): 0x61ff08

Declaring a pointer

dataType* pointerName;

int* ptr;

Initializing a pointer

Pointers should always be initialized before use.

int number = 50;

int* ptr = &number;
  • number stores the value
  • &number gives its address
  • ptr stores that address

Dereferencing a pointer

The dereference operator (*) accesses the value stored at the address held by the pointer.

cout << *ptr;

// Output: 50

Null pointer

A pointer that does not point to any valid object should be initialized to nullptr, which helps avoid undefined behavior caused by uninitialized pointers.

int* ptr = nullptr;

Pointer arithmetic

Pointers can be incremented or decremented to move through contiguous memory locations, such as elements of an array.

ptr++;
ptr--;

Pointer to pointer

A pointer can store the address of another pointer.

int value = 10;

int* ptr = &value;

int** ptr2 = &ptr;

Example 1: Declaring and using a pointer

#include <iostream>
using namespace std;

int main()
{
    int number = 25;

    int* ptr = &number;

    cout << "Value = " << *ptr;

    return 0;
}

// Output: Value = 25

Example 2: Display value and address

#include <iostream>
using namespace std;

int main()
{
    int number = 100;

    int* ptr = &number;

    cout << "Value: " << *ptr << '\n';

    cout << "Address: " << ptr;

    return 0;
}

Example 3: Modify a variable using a pointer

#include <iostream>
using namespace std;

int main()
{
    int marks = 75;

    int* ptr = &marks;

    *ptr = 90;

    cout << marks;

    return 0;
}

// Output: 90

Example 4: Pointer arithmetic with an array

#include <iostream>
using namespace std;

int main()
{
    int numbers[5] = {10, 20, 30, 40, 50};

    int* ptr = numbers;

    for (int i = 0; i < 5; i++)
    {
        cout << *(ptr + i) << " ";
    }

    return 0;
}

// Output: 10 20 30 40 50

Example 5: Pointer to pointer

#include <iostream>
using namespace std;

int main()
{
    int value = 50;

    int* ptr = &value;

    int** ptr2 = &ptr;

    cout << **ptr2;

    return 0;
}

// Output: 50

Common mistakes and pitfalls

  • Dereferencing an uninitialized pointer. Fix: initialize with nullptr or a valid address
  • Dereferencing nullptr. Fix: check if the pointer is not nullptr first
  • Forgetting to initialize a pointer. Fix: always initialize pointers
  • Using a pointer after deleting memory. Fix: set the pointer to nullptr after deletion
  • Confusing * and &. Fix: use & for addresses and * for dereferencing
// Wrong
int* ptr;

cout << *ptr;
// Correct
int value = 10;

int* ptr = &value;

cout << *ptr;

Best practices

  • Always initialize pointers
  • Use nullptr instead of NULL or 0
  • Prefer smart pointers (unique_ptr, shared_ptr) over raw pointers for ownership
  • Check for nullptr before dereferencing when appropriate
  • Keep pointer usage as simple as possible
  • Use references instead of pointers when nullability or reseating isn't required

When not to use this

  • Simple variables or references are sufficient
  • Automatic memory management is preferred
  • Ownership semantics are needed (use smart pointers)
  • Working with standard containers like std::vector instead of manual dynamic arrays

Summary

  • Pointers store memory addresses instead of values
  • The address-of operator (&) obtains a variable's address
  • The dereference operator (*) accesses the value at an address
  • Initialize pointers before using them
  • Use nullptr for pointers that don't currently point to an object
  • Pointer arithmetic allows navigation through contiguous memory
  • Modern C++ often prefers smart pointers for resource management

Frequently asked questions

What is a pointer in C++?

A variable that stores the memory address of another variable.

What is the difference between * and &?

& returns the memory address of a variable, while * declares a pointer and dereferences it to access the pointed-to value.

What is a null pointer?

A pointer that doesn't point to any valid object, represented in modern C++ using nullptr.

Why are pointers important in C++?

They enable direct memory access, dynamic memory allocation, efficient parameter passing, and advanced data structures.

Should I always use raw pointers?

No. Prefer references when appropriate and smart pointers for owning resources; raw pointers suit non-owning access and low-level programming.