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
0x7ffe4ab51024

where “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 int variables.
  • float* to float variables.
  • char* to char, and so on.
  • Even user-defined types (like struct or class) 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 = &num;) 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:

  1. Cannot dereference directly – must cast first
  2. Cannot do pointer arithmetic – no size info
  3. 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 double

Pointer 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 double

Pointer 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 = &num;;   // Single Pointer or First-Level Pointer
int** q = &p;  // Second Pointer or Second-Level Pointer

If there was one more pointer, it would be like int*** r.

int num = 7;
int* p = &num;   // 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 7

It 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.

Similar Posts

  • Reduce Time Complexity with Binary Search Algorithm in DSA

    Do you also wanna optimize your searching speed by using binary search algorithm? If yes! You came to right place….

Leave a Reply

Your email address will not be published. Required fields are marked *