Pointers
References provide another name for an existing object, but C++ also allows us to work directly with memory addresses. In this lesson, you will learn how pointers store addresses and how to access and modify values through them.
Introduction
In the previous lesson, you learned about references, which provide another name for an existing object. C++ also allows programs to work with the memory address of an object.
int number = 100;When this variable is created, the computer stores its value somewhere in memory. The exact address is chosen by the system and may be different each time the program runs.
Variable: number
Address Value
0x1000 ────────► 100Normally, we use the variable name to work with the value. Sometimes, however, a program needs to store and work with the address of an object itself.
C++ provides pointers, which are objects that can store memory addresses.
What is a Pointer?
A pointer is a variable that stores the memory address of another object.
An ordinary variable stores a value directly, while a pointer stores an address that can identify another object.
int number = 100;
int *ptr = &number;ptr
│
│ stores address of number
▼
number ─────► 100| Object | Stores |
|---|---|
| number | The integer value 100 |
| ptr | The address of number |
A pointer is a variable whose value is a memory address.
Why Do We Need Pointers?
Pointers are an important part of C++ because they allow programs to represent optional objects, build dynamic structures, manage resources, interact with low-level systems, and work with dynamically allocated memory.
Without Pointers
- Dynamic linked structures would be difficult to represent.
- Explicit dynamic memory management would not be possible in the same way.
- Interfacing with many low-level APIs would become difficult.
- Representing an optional object through a null address would not be available.
- Many system-level programming techniques would be unavailable.
With Pointers
- Store and work with object addresses.
- Represent an optional object using nullptr.
- Build linked lists, trees, and graphs.
- Work with dynamically allocated objects.
- Interact with operating systems, hardware, and C-style APIs.
Address Storage
Pointers can store the address of compatible objects.
Indirect Access
Pointers can access and modify objects through their addresses.
Dynamic Memory
Pointers are fundamental when working directly with dynamically allocated objects.
Data Structures
Linked lists, trees, and graphs use links between objects.
Optional State
A pointer can hold nullptr to represent that it currently points to no object.
Low-Level Programming
Pointers are widely used when interacting with system APIs and memory-oriented interfaces.
Real-World Analogy
Imagine a hotel. A guest named Rahul is staying in room 101. Instead of carrying Rahul himself, a note can simply contain his room number.
Pointer Note
┌─────────────┐
│ Room 101 │
└──────┬──────┘
│
▼
┌─────────────┐
│ Room 101 │
│ Rahul │
└─────────────┘The room number tells you where Rahul can be found. Similarly, a pointer stores an address that identifies where an object can be accessed.
The pointer is like a note containing a room number. The address tells the program where the target object can be found.
Variables and Memory
Every object used by a running program occupies storage. Consider the following integer variable.
int number = 100;Conceptually, the program has a value stored at some memory address.
Variable Name: number
Memory Address Stored Value
─────────────────────────────────
0x1000 100| Property | Example |
|---|---|
| Variable Name | number |
| Data Type | int |
| Stored Value | 100 |
| Memory Address | 0x1000 (example only) |
Addresses shown in lessons are conceptual examples. Real memory addresses are chosen by the system and may change between executions.
Pointer Declaration & Address-of Operator
To declare a pointer, use the * symbol in the declaration.
data_type *pointer_name;int *ptr;This declares ptr as a pointer to int. It means ptr can store the address of a compatible int object.
| Part | Meaning |
|---|---|
| int | The type of object the pointer can point to |
| * | Indicates a pointer declarator in this declaration |
| ptr | The pointer variable name |
To obtain the address of an object, use the address-of operator &.
int number = 100;
std::cout << &number;The expression &number produces the address of number.
int number = 100;
int *ptr = &number;In int *ptr, * declares a pointer. In *ptr, it dereferences a pointer. In &number, & obtains an address. In int &ref, & declares a reference.
Example 1: Displaying Memory Address
#include <iostream>
int main()
{
int number = 100;
std::cout << number << std::endl;
std::cout << &number;
return 0;
}Explanation
- number is created with the value 100.
- std::cout << number displays the stored value.
- &number produces the address of number.
- std::cout << &number displays that address.
100
0x61ff08The displayed address is only an example. The actual address may differ every time the program runs.
Example 2: Creating a Pointer
The address of an object can be stored in a compatible pointer.
#include <iostream>
int main()
{
int number = 100;
int *ptr = &number;
std::cout << ptr;
return 0;
}Explanation
- number stores the integer value 100.
- int *ptr declares a pointer to int.
- &number obtains the address of number.
- ptr stores that address.
- Printing ptr displays the address stored inside the pointer.
number
Address: 0x1000
┌─────────────┐
│ 100 │
└─────────────┘
▲
│
│ points to
│
ptr
Address: 0x2000
┌─────────────┐
│ 0x1000 │
└─────────────┘| Variable | Example Address | Stored Value |
|---|---|---|
| number | 0x1000 | 100 |
| ptr | 0x2000 | 0x1000 |
ptr has its own storage and its own address. The value stored inside ptr is the address of number.
The Dereference Operator (*)
Once a pointer stores the address of an object, the dereference operator * can be used to access the object through that pointer.
*pointer_nameint number = 100;
int *ptr = &number;
std::cout << *ptr;The expression *ptr means: access the object located at the address stored in ptr.
ptr contains 0x1000
│
▼
Go to address 0x1000
│
▼
Access value 100Dereferencing follows the address stored in a valid pointer and accesses the pointed-to object.
Example 3: Dereferencing a Pointer
#include <iostream>
int main()
{
int number = 100;
int *ptr = &number;
std::cout << *ptr;
return 0;
}Step-by-Step Explanation
- number is created with the value 100.
- &number obtains the address of number.
- ptr stores the address of number.
- *ptr follows the stored address.
- The value of the pointed-to object is accessed.
- The program displays 100.
100| Expression | Meaning |
|---|---|
| number | The value stored in number |
| &number | The address of number |
| ptr | The address stored in the pointer |
| *ptr | The object accessed through the pointer |
If ptr stores &number, then *ptr accesses number.
Example 4: Modifying a Variable Using a Pointer
A valid non-const pointer can also be used to modify the object to which it points.
#include <iostream>
int main()
{
int number = 100;
int *ptr = &number;
*ptr = 250;
std::cout << number;
return 0;
}ptr ─────► number ─────► 100ptr ─────► number ─────► 250250Assigning through *ptr modifies the object pointed to by ptr. In this example, that object is number.
Program Execution Flow
The pointer workflow involves obtaining an address, storing it in a compatible pointer, and dereferencing the pointer only when it refers to a valid object.
Comparisons
Pointers become easier to understand when compared with ordinary variables and references.
Pointer vs Variable
| Feature | Variable | Pointer |
|---|---|---|
| Primary Purpose | Represents an object or value | Stores an address |
| Example Value | 100 | 0x1000 |
| Direct Access | Use the variable name | Use the pointer value to inspect the address |
| Indirect Object Access | Not required | Use dereferencing with * |
| Can Represent No Target | Not in the pointer sense | Yes, using nullptr |
Reference vs Pointer
| Feature | Reference | Pointer |
|---|---|---|
| Concept | Alias for an object | Variable that stores an address |
| Initialization | Must be initialized | Can be initialized to an address or nullptr |
| Null State | A valid reference is expected to refer to an object | Can hold nullptr |
| Reseating | Cannot be reseated | Can store another compatible address later |
| Access Syntax | Normal variable syntax | Dereference with * to access target object |
| Own Stored Value | Reference semantics | Stores an address value |
int number = 100;
int &ref = number;
ref = 250;int number = 100;
int *ptr = &number;
*ptr = 250;A reference acts as another name for an object. A pointer explicitly stores an address and can be changed to point to another compatible object.
Real-World Applications
Dynamic Memory
Pointers can refer to objects created dynamically during program execution.
Data Structures
Linked lists, trees, and graphs use links between nodes.
Game Development
Pointers can be used in object systems, engines, resource management, and low-level APIs.
Operating Systems
Low-level system programming frequently works with addresses and memory-oriented interfaces.
Hardware Interfaces
Embedded and systems programming may use address-based access to hardware resources.
Legacy and C APIs
Pointers are commonly used when interoperating with C libraries and operating system APIs.
int first = 10;
int second = 20;
int *ptr = &first;
ptr = &second;Unlike a reference, a pointer can later store the address of another compatible object.
Advantages of Pointers
Address-Based Access
Pointers allow programs to store and use object addresses explicitly.
Optional Targets
nullptr can represent that a pointer currently points to no object.
Flexible Targeting
A pointer can be changed to point to another compatible object.
Dynamic Objects
Pointers support direct work with dynamically allocated objects.
Complex Structures
Pointers help connect nodes in linked data structures.
Low-Level Control
Pointers are essential in many systems, embedded, and interoperability scenarios.
- Store and work with memory addresses.
- Represent optional object relationships with nullptr.
- Point to different compatible objects over time.
- Support dynamic memory techniques.
- Enable linked data structures.
- Work with low-level and C-style APIs.
- Provide indirect access to objects.
Common Beginner Mistakes
An uninitialized local pointer has an indeterminate value and must not be dereferenced.
A pointer must receive a compatible address, not an ordinary integer value.
A null pointer does not point to an object and must not be dereferenced.
& obtains an address, while * can access an object through a pointer.
A pointer becomes dangerous when the object it points to no longer exists.
// ❌ Dangerous
int *ptr;
std::cout << *ptr;
// ✅ Safe initial state
int *ptr = nullptr;int number = 100;
// ❌ Incorrect
// int *ptr = number;
// ✅ Correct
int *ptr = &number;int *ptr = nullptr;
// ❌ Undefined behavior
// std::cout << *ptr;int *ptr = nullptr;
if (ptr != nullptr)
{
std::cout << *ptr;
}Dereferencing an uninitialized, null, or dangling pointer causes undefined behavior.
Best Practices
- Initialize pointers when they are declared.
- Use nullptr when a pointer intentionally has no target.
- Dereference a pointer only when it refers to a valid object.
- Check nullable pointers before dereferencing them.
- Use meaningful names such as studentPtr or currentNode.
- Prefer references when nullability and reseating are not required.
- Avoid raw owning pointers in modern C++ when standard resource-management types are more appropriate.
- Ensure the pointed-to object remains alive while the pointer is used.
- Avoid returning pointers to local variables.
- Keep pointer usage as simple and local as possible.
int *ptr = nullptr;if (ptr != nullptr)
{
std::cout << *ptr;
}int number = 100;
int *ptr = &number;
std::cout << *ptr;Use raw pointers mainly for non-owning relationships and low-level interfaces. For ownership and resource management, modern C++ often uses automatic objects, containers, and smart pointers.
Frequently Asked Questions
What is a pointer?
A pointer is a variable that stores a memory address.
Which operator obtains the address of a variable?
The address-of operator & produces the address of an object.
Which operator accesses an object through a pointer?
The dereference operator * accesses the pointed-to object.
What does int *ptr mean?
It declares ptr as a pointer that can store the address of a compatible int object.
Can a pointer point to another variable later?
Yes. A pointer can be assigned another compatible address.
What is nullptr?
nullptr is the modern C++ null pointer value used to indicate that a pointer currently points to no object.
Can nullptr be dereferenced?
No. Dereferencing a null pointer causes undefined behavior.
What is the difference between ptr and *ptr?
ptr is the address stored in the pointer, while *ptr accesses the object at that address.
What is the difference between a reference and a pointer?
A reference acts as an alias, while a pointer stores an address and can represent no target or point to another compatible object later.
Why are pointers important?
Pointers are important for dynamic memory, linked data structures, optional object relationships, low-level programming, and interoperability with many APIs.
Key Takeaways
- A pointer is a variable that stores a memory address.
- The address-of operator & obtains the address of an object.
- The dereference operator * accesses an object through a pointer.
- If ptr stores &number, then *ptr accesses number.
- A pointer has its own storage and can store the address of another object.
- Pointers can modify pointed-to objects when the type allows modification.
- Pointers can be changed to point to different compatible objects.
- nullptr represents a pointer with no current target.
- Invalid pointers must never be dereferenced.
- Pointers are important for dynamic memory and linked data structures.
- Pointers are widely used in low-level programming and C-style APIs.
- Understanding pointers is essential for advanced C++ programming.
Summary
Pointers are one of the most important low-level features of C++. A pointer stores an address and can provide indirect access to another object.
The address-of operator & obtains the address of an object, while the dereference operator * accesses the object through a valid pointer.
Pointers can be used to read and modify objects, represent optional relationships with nullptr, build linked data structures, work with dynamic memory, and interact with system-level APIs.
Pointers also require careful handling. Uninitialized, null, and dangling pointers must never be dereferenced. Understanding pointer validity and object lifetime is essential for writing safe C++ programs.
With references and pointers understood, you are ready to begin object-oriented programming by learning how C++ classes combine data and behavior into reusable types.