Question
I have recently started learning basic C++ after working with higher-level languages, and I want to better understand pointers.
I have three main questions:
- Why would I use pointers instead of ordinary variables?
- When and where should pointers be used in C++?
- How do pointers work with arrays?
I am looking for a beginner-friendly explanation with simple examples.
Short Answer
By the end of this page, you will understand what pointers are in C++, why they exist, when they are useful, and how they relate to arrays. You will also see practical examples, common mistakes, and how pointers appear in real C++ code.
Concept
Pointers are variables that store memory addresses instead of storing a regular value directly.
For example, an int stores a number such as 42. A pointer to int stores the location in memory where an int lives.
int x = 42;
int* p = &x;
Here:
xstores the value42&xmeans "the address ofx"pstores that address*pmeans "the value at the address stored inp"
Why pointers matter
Pointers are important in C++ because they let you:
- work with data without copying it
- share access to the same object
- build dynamic data structures like linked lists and trees
- interact with arrays and low-level memory
- pass objects to functions efficiently
- represent optional access to something with
nullptr
Why not just use normal variables?
Normal variables are perfect when you only need to store and use a value directly.
int x = 10;
But sometimes you need one of these behaviors:
- modify a variable from another place
- avoid copying a large object
- create something dynamically at runtime
- refer to different elements in memory one by one
That is where pointers become useful.
A key idea
Pointers are not "better" than normal variables. They solve different problems.
Use a normal variable when you want to store a value. Use a pointer when you need to store where a value is.
Mental Model
Think of memory like a street full of houses.
- A normal variable is the thing inside a house.
- A pointer is a piece of paper with the house address written on it.
If you have the address, you can go to that house and read or change what is inside.
int score = 100;
int* ptr = &score;
scoreis the value in the houseptris the note with the address*ptrmeans you walk to that address and access the value there
This explains why pointers are powerful:
- multiple pointers can refer to the same object
- changing
*ptrchanges the original value - you can move through nearby memory, such as array elements
It also explains why pointers are risky:
- if the address is wrong, you go to the wrong house
- if the house no longer exists, the pointer is invalid
- if the pointer stores no address, it should be
nullptr
Syntax and Examples
Basic pointer syntax
int x = 5; // normal variable
int* p = &x; // pointer to x
Important symbols
&xgets the address ofxint* pdeclares a pointer toint*pdereferences the pointer, meaning "get the value stored at that address"
Reading and writing through a pointer
#include <iostream>
using namespace std;
int main() {
int x = 5;
int* p = &x;
cout << x << "\n"; // 5
cout << *p << "\n"; // 5
*p = 20;
cout << x << "\n"; // 20
}
The line *p = 20; changes x because p points to x.
Pointers and functions
Pointers can be used to let a function modify the original variable.
#include <iostream>
using namespace std;
void setToZero(int* p) {
*p = 0;
}
int main() {
int value = 10;
setToZero(&value);
cout << value << "\n"; // 0
}
The function receives the address of value, then changes the original variable through that address.
Pointers with arrays
Array names are closely related to pointers.
#include <iostream>
using namespace std;
int main() {
int nums[3] = {10, 20, 30};
cout << nums[0] << "\n"; // 10
cout << *(nums + 1) << "\n"; // 20
}
Why does *(nums + 1) work?
numsrefers to the first elementnums + 1moves to the next element*(nums + 1)gets the value there
This is why pointers and arrays are strongly connected in C++.
Step by Step Execution
Consider this example:
#include <iostream>
using namespace std;
int main() {
int x = 7;
int* p = &x;
*p = *p + 3;
cout << x << "\n";
}
Step-by-step
1. int x = 7;
A normal integer variable named x is created and stores 7.
2. int* p = &x;
A pointer named p is created.
It stores the address of x.
You can think of it like this:
x->7p-> address ofx
3. *p = *p + 3;
This line uses the pointer to read and update x.
*pon the right side reads the value at the address stored inp- that value is
7 7 + 3becomes10*pon the left side writes10back into that same memory location
So x becomes 10.
4. cout << x << "\n";
The program prints 10.
Key lesson
The pointer did not create a copy of x. It gave another way to access the same variable.
Real World Use Cases
Pointers appear in many practical C++ situations.
1. Modifying data through function calls
When a function needs to update a variable or object owned by the caller, pointers can be used.
void increment(int* n) {
(*n)++;
}
2. Working with arrays and buffers
Low-level code often processes memory ranges using pointers.
void printArray(const int* arr, int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
}
3. Dynamic memory
When the amount of data is known only at runtime, pointers can refer to dynamically allocated memory.
int* p = new int(42);
delete p;
In modern C++, this is usually replaced with safer tools such as smart pointers and containers.
4. Optional ownership or optional object access
A pointer can be nullptr, which means "points to nothing".
int* p = nullptr;
This can represent the absence of a value or object.
5. Building data structures
Linked lists, trees, graphs, and many system-level structures connect objects using pointers.
struct Node {
int value;
Node* next;
};
6. Interfacing with operating systems, hardware, and libraries
Many system APIs and older C libraries use raw pointers for data access.
Real Codebase Usage
In real C++ projects, developers use pointers carefully.
Common patterns
Guarding against null pointers
void printValue(const int* p) {
if (p == nullptr) {
return;
}
cout << *p << "\n";
}
This is a guard clause: it exits early if the pointer is invalid.
Read-only access with const
void show(const int* p) {
if (p) {
cout << *p << "\n";
}
}
const int* means the function should not modify the value being pointed to.
Iterating through arrays or ranges
void printAll(const int* begin, const int* end) {
while (begin != end) {
cout << *begin << " ";
begin++;
}
}
This style is common in lower-level code and library internals.
Using smart pointers instead of raw ownership
In modern C++, developers often avoid owning raw pointers directly.
#include <memory>
using namespace std;
unique_ptr<int> p = make_unique<int>(42);
This helps prevent memory leaks.
Using references when a null value is not needed
If a function must receive a valid object, references are often preferred.
void doubleValue(int& n) {
n *= 2;
}
In real codebases:
- raw pointers often mean non-owning access
nullptris checked before dereferencing- smart pointers manage ownership
- references are used when an object must exist
Common Mistakes
1. Dereferencing an uninitialized pointer
Broken code:
int* p;
*p = 5;
Problem:
pdoes not point to a valid memory location- dereferencing it causes undefined behavior
Fix:
int x = 0;
int* p = &x;
*p = 5;
Or initialize with nullptr if it should point to nothing yet.
int* p = nullptr;
2. Dereferencing nullptr
Broken code:
int* p = nullptr;
cout << *p;
Fix:
if (p != nullptr) {
cout << *p;
}
3. Confusing * in declaration and dereference
int* p = &x; // declaration: p is a pointer
cout << *p; // dereference: read the value pointed to by p
The same symbol is used in two related but different ways.
4. Returning pointers to local variables
Broken code:
int* bad() {
int x = 10;
return &x;
}
Problem:
xis destroyed when the function ends- the returned pointer becomes dangling
5. Forgetting to free manually allocated memory
Broken code:
int* p = new int(42);
Problem:
- if
delete p;is never called, memory leaks
Better modern approach:
auto p = std::make_unique<int>(42);
6. Pointer arithmetic mistakes with arrays
Broken code:
int arr[3] = {1, 2, 3};
cout << *(arr + 5);
Problem:
- this goes beyond the array bounds
- accessing out of range memory is undefined behavior
7. Assuming arrays and pointers are exactly the same
They are closely related, but not identical.
- an array has a fixed size
- a pointer is just a variable storing an address
Comparisons
| Concept | What it stores | Can be null? | Typical use |
|---|---|---|---|
| Normal variable | A direct value | No | Storing data like int x = 5; |
| Pointer | Address of a value | Yes | Optional access, dynamic memory, arrays, sharing data |
| Reference | Another name for an existing value | No | Function parameters when a valid object must exist |
Pointer vs reference
int x = 10;
int* p = &x;
int& r = x;
pcan later point somewhere elsepcan benullptrrmust refer to a valid object immediatelyrcannot be reseated to another object
Array vs pointer
| Feature | Array | Pointer |
|---|---|---|
| Owns a fixed group of elements | Yes | No |
| Knows its size automatically in most expressions | No | No |
| Can be reassigned | No | Yes |
| Supports indexing | Yes | Yes, if pointing into an array |
Example:
int arr[3] = {1, 2, 3};
int* p = arr;
p points to the first element of arr, but arr itself is not just a normal pointer variable.
Raw pointer vs smart pointer
| Type | Memory management | Safer ownership? | Common use |
|---|---|---|---|
Raw pointer (T*) | Manual or non-owning | Less safe | Non-owning access, low-level APIs |
unique_ptr<T> | Automatic | Yes | Exclusive ownership |
shared_ptr<T> | Automatic shared ownership | Safer but heavier | Shared ownership when needed |
Cheat Sheet
Basic syntax
int x = 5;
int* p = &x;
&x-> address ofxp-> pointer storing that address*p-> value at that address
Read and write
cout << *p;
*p = 10;
Null pointer
int* p = nullptr;
Always check before dereferencing if null is possible.
Arrays and pointers
int arr[3] = {10, 20, 30};
int* p = arr;
arr[0]is the first element*arris also the first element*(arr + 1)is the second element
Function parameter examples
void update(int* p) {
if (p) {
*p = 100;
}
}
Rules to remember
- initialize pointers
- do not dereference invalid pointers
- do not go past array bounds
- do not return pointers to local variables
- prefer references when null is not needed
- prefer smart pointers for ownership in modern C++
Common forms
const int* p; // pointer to const int
int* const p2 = &x; // const pointer to int
const int* p-> cannot change the pointed value throughpint* const p2->p2cannot point somewhere else after initialization
FAQ
Why do pointers exist in C++?
Pointers exist so programs can work directly with memory addresses. This allows efficient data access, dynamic memory management, shared access to objects, and low-level programming.
Are pointers faster than normal variables?
Not automatically. Pointers are not a speed trick by themselves. They are useful when avoiding copies, sharing access, or working with memory directly.
When should I use a pointer instead of a reference in C++?
Use a pointer when the value might be absent (nullptr) or when reseating to a different object is useful. Use a reference when the object must always exist.
Are arrays and pointers the same in C++?
No. They are closely related, and arrays often decay to pointers in expressions, but an array is a fixed block of elements while a pointer is just a variable holding an address.
Is NULL the same as nullptr?
In modern C++, prefer nullptr. It is the proper null pointer literal and avoids ambiguity.
Should I use new and delete often in modern C++?
Usually no. Prefer containers like std::vector and smart pointers like std::unique_ptr unless you have a specific low-level need.
Can a pointer change the original variable?
Yes. If a pointer points to a variable, writing through the pointer changes that original variable.
What is a dangling pointer?
A dangling pointer points to memory that is no longer valid, such as a local variable that has gone out of scope or memory that was already deleted.
Mini Project
Description
Build a small C++ program that demonstrates the three most important beginner pointer skills: pointing to a normal variable, modifying a value through a pointer, and traversing an array using a pointer. This project is useful because it combines the exact scenarios where beginners first encounter pointers.
Goal
Create a program that uses a pointer to modify a variable and then uses another pointer to print all elements of an array.
Requirements
- Create an integer variable and a pointer that stores its address.
- Change the integer value through the pointer.
- Create an integer array with at least five elements.
- Use a pointer to print each array element.
- Show output before and after the variable is changed.
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.