C++ Pointers


Introduction

In C++, pointers are variables that store the memory address of another variable. Pointers are a powerful feature that allows you to directly manipulate memory and can improve performance, especially in low-level system programming, dynamic memory management, and working with data structures like linked lists, trees, and graphs.

This blog post will cover:

  • What pointers are and why they're important.
  • How to declare and initialize pointers.
  • How to use pointers with variables, arrays, functions, and classes.
  • Practical examples of pointers in action.

Let’s dive into the world of C++ pointers!


1. What is a Pointer?

A pointer is a variable that holds the memory address of another variable. Rather than storing a data value directly, it stores the address where the value is located in memory.

Syntax for Declaring a Pointer:

data_type* pointer_name;
  • data_type is the type of data the pointer will point to (e.g., int, float, char).
  • The asterisk * is used to denote that the variable is a pointer.

Example:

int num = 5;
int* ptr = #  // 'ptr' points to the memory address of 'num'

In the above example:

  • &num is the address-of operator, which returns the memory address of the variable num.
  • ptr is a pointer that stores the memory address of num.

2. Dereferencing a Pointer

Dereferencing a pointer means accessing the value stored at the address the pointer is pointing to. This is done using the asterisk * operator.

Example:

int num = 5;
int* ptr = #  // Pointer points to num

cout << "Value of num: " << *ptr << endl;  // Dereferencing the pointer

Output:

Value of num: 5

Explanation:

  • *ptr dereferences the pointer, giving you access to the value stored at the address ptr is pointing to (which is 5 in this case).

3. Pointer Initialization

Pointers need to be initialized before they are used. A pointer that is not initialized is called a wild pointer and can lead to unpredictable behavior or crashes.

Example of Uninitialized Pointer:

int* ptr;  // Wild pointer - not initialized
cout << *ptr;  // Undefined behavior (can cause crash)

Safe Pointer Initialization:

You can initialize pointers in two ways:

  • By setting it to nullptr (recommended in modern C++).
  • By assigning it to the address of a valid variable.
int num = 10;
int* ptr = &num;  // Pointer pointing to num

 Or, initialize it to nullptr if it doesn't point to any valid memory initially:

int* ptr = nullptr;

4. Pointers and Arrays

Arrays and pointers are closely related in C++. An array name is essentially a pointer to the first element of the array. This allows you to use pointers to traverse and manipulate arrays efficiently.

Example:

int arr[] = {1, 2, 3, 4, 5};
int* ptr = arr;  // Pointer to the first element of the array

cout << "First element: " << *ptr << endl;  // Dereferencing the pointer to get the first element

// Pointer arithmetic
cout << "Second element: " << *(ptr + 1) << endl;  // Moving to the next element

Output:

First element: 1
Second element: 2

Explanation:

  • ptr points to the first element of arr. Using pointer arithmetic, *(ptr + 1) moves the pointer to the second element.

5. Pointers to Functions

In C++, you can also have pointers to functions. A function pointer can be used to call a function indirectly.

Example:

#include <iostream>
using namespace std;

void greet() {
    cout << "Hello, World!" << endl;
}

int main() {
    void (*funcPtr)() = &greet;  // Function pointer
    funcPtr();  // Calling the function using the pointer
    
    return 0;
}

Output:

Hello, World!

Explanation:

  • void (*funcPtr)() is a function pointer that points to a function that takes no arguments and returns void.
  • funcPtr() calls the greet() function indirectly.

6. Pointers to Classes and Objects

In C++, pointers are often used to work with objects dynamically created in memory (using new keyword). This allows for more flexible memory management, especially when dealing with large data structures.

Example:

#include <iostream>
using namespace std;

class Person {
public:
    string name;
    int age;
    Person(string n, int a) : name(n), age(a) {}
};

int main() {
    // Creating an object dynamically using 'new'
    Person* ptr = new Person("John Doe", 30);
    
    // Accessing class members using pointer
    cout << "Name: " << ptr->name << endl;
    cout << "Age: " << ptr->age << endl;
    
    // Don't forget to free the memory
    delete ptr;  // Free dynamically allocated memory
    
    return 0;
}

Output:

Name: John Doe
Age: 30

Explanation:

  • Person* ptr = new Person("John Doe", 30); dynamically allocates memory for a Person object on the heap.
  • The -> operator is used to access the class members through the pointer.
  • delete ptr; frees the memory allocated by new.

7. Pointer Arithmetic

Pointers can be incremented or decremented to point to different memory locations. This is known as pointer arithmetic. This feature is particularly useful when working with arrays.

Example:

int arr[] = {10, 20, 30, 40, 50};
int* ptr = arr;

cout << "First element: " << *ptr << endl;    // 10
ptr++;  // Move the pointer to the next element
cout << "Second element: " << *ptr << endl;   // 20

Explanation:

  • ptr++ increments the pointer to point to the next memory location (next element in the array).

8. Dynamic Memory Allocation

C++ provides two operators, new and delete, for dynamic memory allocation and deallocation. This allows you to allocate memory at runtime and frees up memory when you're done with it.

Example of Dynamic Memory Allocation:

int* ptr = new int;  // Allocates memory for one integer
*ptr = 100;  // Assigning value to the allocated memory

cout << "Dynamically allocated value: " << *ptr << endl;  // 100

delete ptr;  // Deallocate memory

Explanation:

  • new int allocates memory on the heap for a single integer.
  • delete ptr frees the allocated memory.

9. Pointers to Constants

You can also declare pointers to constants, which prevents the modification of the value the pointer is pointing to.

Example:

const int num = 10;
const int* ptr = &num;

cout << "Value: " << *ptr << endl;
// *ptr = 20;  // Error: cannot modify a constant value

Explanation:

  • const int* ptr is a pointer to a constant integer. You cannot modify the value through ptr.

10. Null Pointers

A null pointer is a pointer that does not point to any valid memory location. It is usually set to nullptr in modern C++, which is a type-safe way of indicating that the pointer is not pointing to any object.

Example:

int* ptr = nullptr;  // Null pointer

if (ptr == nullptr) {
    cout << "Pointer is null" << endl;
}

Output:

Pointer is null

Explanation:

  • nullptr is used to initialize a pointer to indicate that it doesn't point to any memory location.