Quick Answer

A pointer in C++ is a variable that stores the memory address of another variable instead of a normal value. You use the & operator to get a variable's address and the * operator to read or change the value at that address. Pointers let you share and modify data across functions, but you must initialize them (use nullptr when empty) and never use one after the memory it points to is gone.

What Is a Pointer?

If you are learning C++, sooner or later you will meet pointers. They have a scary reputation, but the core idea is simple. Pointers in C++ are just variables that store a memory address the location of another variable rather than a plain value like 5 or 'a'.

Think of your computer's memory as a very long street of houses. Every house has a unique number on it its address. When you create a normal variable, C++ puts a value inside one of those houses. A pointer does not hold the value itself; it holds the house number where the value lives. If you know the address, you can walk to that house and read or change what is inside.

Why bother? Because passing a small address around is cheaper than copying large data, and it lets different parts of your program share and update the very same variable. That sharing is the "why" behind almost every real use of pointers, so keep the house-and-address picture in your head as we go.

The & and * Operators

Two operators do most of the work with pointers:

  • & (address-of): placed before a variable, it gives you that variable's memory address.
  • * (dereference): placed before a pointer, it gives you the value stored at the address the pointer holds.

Here is the part that confuses beginners: the * symbol is used in two different ways. In a declaration like int* p; it means "p is a pointer to an int." In an expression like *p = 10; it means "go to the address in p and use the value there." Same symbol, two jobs. Read the line's context and it becomes clear which one you are looking at.

Declaring Your First Pointer

Let's put both operators together in a program you can compile and run:

#include <iostream>
using namespace std;

int main() {
    int age = 25;      // a normal variable
    int* p = &age;     // p stores the ADDRESS of age

    cout << "Value of age:      " << age << endl;
    cout << "Address of age:    " << p   << endl;
    cout << "Value via pointer: " << *p  << endl;

    *p = 30;           // change age THROUGH the pointer
    cout << "age is now:        " << age << endl;
    return 0;
}

The line *p = 30; never mentions age, yet it changes it. That is the key power of pointers: through the address, you reach the original variable. The printed address will look like a long hex number such as 0x7ffd..., and it changes every time you run the program which is completely normal, because your operating system loads the program into different memory each time.

Null Pointers and nullptr

Sometimes you have a pointer but nothing useful for it to point to yet. For that, C++ gives you nullptr a special value meaning "this pointer points to nothing." Always prefer nullptr over the old NULL or the bare number 0, because it is clearer and safer.

int* p = nullptr;   // an empty pointer

if (p != nullptr) {
    cout << *p;     // only reached if p points somewhere real
} else {
    cout << "Pointer is empty";
}

The golden rule: never dereference a null pointer. Writing *p when p is nullptr will crash your program. Checking if (p != nullptr) before using it is a simple habit that prevents a whole class of bugs.

Pass-by-Reference With Pointers

By default, C++ passes arguments by value, meaning the function gets a copy. Changes to the copy do not affect the original. Pointers let a function reach back and modify the caller's variable this is often called pass-by-reference.

#include <iostream>
using namespace std;

void addTen(int* n) {
    *n = *n + 10;      // change the ORIGINAL variable
}

int main() {
    int marks = 40;
    addTen(&marks);       // pass the ADDRESS of marks
    cout << marks << endl;  // prints 50
    return 0;
}

Because we passed &marks (its address), the function edits the real marks, not a copy. C++ also has true references (written int& n) that are cleaner for this exact job, but seeing the pointer version first helps you understand what is really happening underneath.

Common Pitfalls to Avoid

Most pointer pain comes from two mistakes. Learn to spot them early and they stop being scary.

1. Uninitialized pointers

A pointer that you declare but never set holds a random garbage address. Writing through it corrupts unknown memory:

int* p;        // BAD: points to a random address
*p = 10;       // undefined behaviour: crash or silent corruption

Fix: always initialise. Use int* p = nullptr; if you have nothing to point to yet, or point it at a real variable right away with int* p = &age;.

2. Dangling pointers

A dangling pointer points to memory that no longer exists. A classic mistake is returning the address of a local variable:

int* makePointer() {
    int x = 5;
    return &x;    // BAD: x is destroyed when the function ends
}

The same problem appears after you free heap memory with delete:

int* p = new int(5);
delete p;      // memory is released
// *p = 10;    // BAD: p now dangles
p = nullptr;   // good habit: set to nullptr after delete

Using a dangling pointer is undefined behaviour: sometimes it seems to "work," sometimes it crashes, which makes these bugs hard to track down.

Pointers vs References

Beginners often mix up pointers and references. Here is a quick comparison to keep them straight:

QuestionPointerReference
Can be null / empty?YesNo
Can be reassigned to point elsewhere?YesNo
Needs * to read the value?YesNo
Good for simple pass-by-reference?PartialYes

Rule of thumb: reach for a reference when you simply need to modify an argument, and use a pointer when the thing might be absent (nullptr) or when you need to change what it points to.

Best Practices and Recommendation

Pointers reward a few steady habits:

  • Always initialise a pointer, with nullptr if nothing else.
  • Check for nullptr before you dereference.
  • Set a pointer to nullptr after delete so it cannot dangle.
  • Match every new with exactly one delete or, better, prefer the modern tools below.

In real, modern C++ you will lean on smart pointers (std::unique_ptr and std::shared_ptr) and standard containers like std::vector, which manage memory for you and remove most manual new/delete. But you still need to understand raw pointers first, because they are the foundation everything else is built on.

Want to practise with guided lessons and exercises? Our free C++ course walks you through pointers, memory, and more at a beginner's pace.

Frequently Asked Questions

What is a pointer in C++ in simple words?

A pointer is a variable that stores the memory address of another variable instead of a normal value. If a regular variable is a house with a value inside, a pointer holds the house number so you can find and change that value from somewhere else in your code.

What is the difference between & and * in C++?

The & (address-of) operator gives you the memory address of a variable, so &age means "the address of age." The * (dereference) operator does the reverse: given a pointer, *p means "the value stored at the address p holds." You use & to make a pointer and * to use it.

What is a null pointer and why use nullptr?

A null pointer points to nothing, and in modern C++ you write it as nullptr. It is useful as a clear "empty" state, but you must never dereference it check if (p != nullptr) first, because reading *p on a null pointer crashes the program.

What is a dangling pointer?

A dangling pointer points to memory that has already been destroyed or freed for example, the address of a local variable after its function returns, or a pointer used after delete. Using one is undefined behaviour. Setting a pointer to nullptr right after you free it helps you avoid this.

Should beginners use pointers or references?

For simply modifying a function argument, references are cleaner and safer because they cannot be null. Use pointers when the value might be absent or when you need to change what it points to. Learn both, but understand raw pointers first since they explain how references work underneath.