Pointers in C/C++: Best Deep Dive Explanation

Throughout my CS degree, pointers in C/C++ have often been confusing and problematic and also extremely time-consuming during revision due to no proper notes or documentation. Here in this article I will be shedding light on the knowledge gained through setbacks, failures and the common struggles of CS students and tech enthusiasts — and how I eventually ended learning this concept after avoiding it for a year. So, sit back and enjoy the journey through the historic Times of Coding…
What is a Pointer?
Let us derive something interesting from the word itself “Point-er”. When you read it the first thing that would come to your mind is that it would mean “pointing towards something”, just like when you point to something with your fingers. A similar and a very common real life analogy, the arrow icon that depicts the mouse movement on the screen is called a pointer since it also points or direct towards an icon on the screen.
In Computer Science, it refers to a type of variable that is used to point towards another variable in computer memory (RAM). But how? It does this by storing the memory address of the variable to which it points.
How is a pointer different from a variable?
It is to be clarified that a variable stores the actual value whereas the pointer stores the address of that variable. An analogy for this is that if your variable is a house, then a pointer is like the house’s address written on a piece of paper.
Another difference is the access. The data stored in a variable is retrieved directly whereas to access the data in pointers, indirect path is followed. Next difference is the size. Size of a variable depends on the size of its data type (eg., for int 4 bytes). Size of address on the other hand is usually 8 bytes on 64-bit architectures. Arithmetic operations performed is different too. The operations performed on variables are simple and normal math operations. But pointers act in a different manner in this regard which we will be explaining in the Arithmetic Pointers section.
Pointer Declaration and Initialization
To initialize a pointers in C/C++, a data type followed by an asterisk * is used like int*, and then the name of the pointer variable.
There are two special symbols used with pointers:
*— Used to declare a pointer OR dereference a pointer&— Used to get the address of a variable
#include
using namespace std;
int main() {
int num = 7; // A number to which we will point
int* p; // Declaring that p is a pointer to an int
p = # // p stores the address of num
cout << p << endl; // Outputs the memory address of num
cout << *p << endl; // Dereferences p, outputs 7 (value of num)
return 0;
}Here,
int* p means p is a pointer to an integer.
&num gets the memory address of variable num.
p = &num stores that address in pointer p.

Here, it can be seen that variable (num) occupies the address 201-204 since it is an integer. Pointer (p) stores 201 as the reference address of the num.
Address-of (&) and Dereference (*) Operators
Pointers in C/C++ use these two operators; & and *. Address-of (&) operator, also known as reference operator, gives the address of the variable with which it is used. For example,
int num = 7;
cout << num << endl;
cout << &num << endl;Here, the output will be
7
0x7ffe4ab51024where “0x7ffe4ab51024” is the address of num in memory. So when we use *p, it means: “give me the value stored at the memory location p is pointing to.”
Now, the dereference operator (*) is used to first declare a pointer and after that at any point it is used for dereferencing. Which means that whenever it is used as *pointer, it would simply act as a mirror to the variable. So, when you see *pointer, assume it is that variable to which it points.
Strong Typing of Pointers
Pointers in C/C++ are strongly typed, meaning:
- int* can only point to
intvariables. - float* to
floatvariables. - char* to
char, and so on. - Even user-defined types (like
structorclass) require corresponding pointer types.
Why does the data type matter if pointers just store addresses?
Because when dereferencing (using *), the compiler needs to know how many bytes to read from that address. Different types use different memory sizes:
sizeof(float) = 4 bytes
sizeof(int) = 4 bytes
sizeof(char) = 1 byte there can’t be a single generic data type to reference back to all. Let us look at it a little deeper in our memory. Let us consider we have an integer num = 2280.

It occupied 4 memory units to stores the integer. For a char pointer (char*) meaning if the integer num was pointed by char (char* ch = #) then it would just contain the address (332) ,altering the actual value. For this reason it is not possible.
Null Pointer
A pointer that does not point to any valid address or memory location is known as “null pointer”. It is like having an empty address where there is no house. It is used to indicate that the pointer is not currently assigned to any object or memory address.
int* ptr = nullptr; // C++11 way (PREFERRED)
int* ptr = NULL; // C way (still works )
int* ptr = 0; // Old way (it is not recommended)This method is used to safely declare a pointer before assigning a valid address. It also tells us that whether a pointer is pointing to something or not. It even helps us in error handling in functions which return pointers.
#include
using namespace std;
int main() {
int* ptr = nullptr; // The pointer is declared null
if (ptr == nullptr) { //Here it is checked whether the pointer is empty or not
cout << "Pointer is null!" << endl;
} else {
cout << "Pointer is not null." << endl;
}
return 0;
}
What are void pointers?
A void pointer is a generic pointer that can point to any data type. It is like a universal container that doesn’t care about what type of data it holds. Though it can point to any data type but for dereferencing the pointer has to be first typecasted.
It is declared as:
void* ptr; <em>// Can point to anything!</em>It tells us that the pointer points to a memory but does not specify what type of data it points to.
Key Rules:
- Cannot dereference directly – must cast first
- Cannot do pointer arithmetic – no size info
- Can point to any data type
One of its basic usage is given below:
int x = 10;
char ch = 'N';
double d = 3.142;
void* voidPtr; <em>// Generic pointer</em>
<em>// Can point to any type</em>
voidPtr = &x; <em>// Points to int</em>
voidPtr = &ch; <em>// Now points to char </em>
voidPtr = &d; // And now to a doublePointer Arithmetic
Pointer Arithmetic is the concept of performing mathematical operations (like ‘+’ or ‘-‘) on pointers. The key aspect of this is that when you add/subtract pointer it moves by the size of the data type of variable, not simply by 1 unit. For example:
int* ptr;
ptr = ptr + 1 //moves by 4 bytes - size of int
char* ptr;
ptr = ptr + 1 //moves 1 byte - size of char
double* ptr;
ptr = ptr + 1 //moves 8 byte - size of doublePointer to Pointer
A pointer to pointer, also known as double pointers in c/c++, stores the address of the memory location of another pointer. It requires an extra asterisk (*) than the pointer it points to. The number of pointers used elaborates the level of the pointer i.e.,
- Single Pointer:
int* ptr - Double Pointer:
int** ptr - Triple Pointer:
int*** ptr(and so on…)
int num = 7;
int* p = #; // Single Pointer or First-Level Pointer
int** q = &p; // Second Pointer or Second-Level PointerIf there was one more pointer, it would be like int*** r.
int num = 7;
int* p = # // First-level pointer
int** q = &p; // Second-level pointer
int*** r = &q; // Third-levelpointer
cout << *p; // Prints 7
cout << **q; // Also prints 7
cout << ***r; // This one too prints 7It is for the reason that one asterisk means that r is a pointer to q. The, the second asterisk means that q is a pointer to p and third one p, is the pointer to num.
***r == r → q → p → num
Finally, we have covered lot about pointers in C/C++, why they are used? and how we go and play with them like master. If you have any query left behind, feel free and hit the comment section. We will be pleased to sort out the matter.
