Back to C++ Home

Pointers & Memory

Pointers are one of the most powerful and fundamental features of C++. They provide direct access to memory addresses, enabling efficient memory management, dynamic allocation, and low-level programming. Understanding pointers is essential for advanced C++ programming, as they form the basis for dynamic data structures, efficient function parameter passing, and resource management. While pointers can be challenging, mastering them unlocks the full potential of C++.

Introduction to Pointers

A pointer is a variable that stores the memory address of another variable. Pointers provide direct access to memory, enabling efficient memory management and dynamic allocation. Unlike regular variables that store values, pointers store addresses, allowing you to indirectly access and modify data.

Pointers are crucial for several reasons: they enable dynamic memory allocation (creating variables at runtime), efficient parameter passing (avoiding copying large objects), implementing data structures (linked lists, trees), and interfacing with hardware or system APIs. However, they require careful management to avoid memory leaks, dangling pointers, and undefined behavior.

1. Basic Pointer Operations

Declaration and Initialization

#include <iostream>
using namespace std;

int main() {
    int num = 10;
    int *ptr;        // Pointer declaration
    ptr = &num;      // Store address of num
    
    cout << "Value of num: " << num << endl;
    cout << "Address of num: " << &num << endl;
    cout << "Value of ptr: " << ptr << endl;
    cout << "Value pointed by ptr: " << *ptr << endl;
    
    return 0;
}

Pointer Operators

  • & (Address of): Returns the address of a variable
  • * (Dereference): Returns the value at the address stored in pointer

2. Pointer Arithmetic

Pointers can be incremented, decremented, and used in arithmetic operations:

#include <iostream>
using namespace std;

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr = arr;  // Points to first element
    
    cout << *ptr << endl;      // 10
    ptr++;                      // Move to next element
    cout << *ptr << endl;      // 20
    ptr += 2;                   // Move 2 elements ahead
    cout << *ptr << endl;      // 40
    
    // Traverse array using pointer
    ptr = arr;
    for (int i = 0; i < 5; i++) {
        cout << *(ptr + i) << " ";
    }
    cout << endl;
    
    return 0;
}

3. Pointers and Arrays

#include <iostream>
using namespace std;

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int *ptr = arr;
    
    // Array name is a pointer to first element
    cout << "arr = " << arr << endl;
    cout << "&arr[0] = " << &arr[0] << endl;
    cout << "ptr = " << ptr << endl;
    
    // Accessing elements
    cout << arr[2] << endl;      // 3
    cout << *(arr + 2) << endl;  // 3
    cout << ptr[2] << endl;      // 3
    cout << *(ptr + 2) << endl;  // 3
    
    return 0;
}

4. Pointers to Pointers

#include <iostream>
using namespace std;

int main() {
    int num = 10;
    int *ptr = &num;
    int **pptr = &ptr;  // Pointer to pointer
    
    cout << "num = " << num << endl;
    cout << "*ptr = " << *ptr << endl;
    cout << "**pptr = " << **pptr << endl;
    
    return 0;
}

5. Dynamic Memory Allocation

C++ provides new and delete operators for dynamic memory management:

Single Variable

#include <iostream>
using namespace std;

int main() {
    int *ptr = new int;  // Allocate memory
    *ptr = 100;
    
    cout << "Value: " << *ptr << endl;
    
    delete ptr;  // Deallocate memory
    ptr = nullptr;  // Good practice
    
    return 0;
}

Array

#include <iostream>
using namespace std;

int main() {
    int size;
    cout << "Enter size: ";
    cin >> size;
    
    int *arr = new int[size];  // Dynamic array
    
    for (int i = 0; i < size; i++) {
        arr[i] = i * 10;
    }
    
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
    
    delete[] arr;  // Deallocate array
    arr = nullptr;
    
    return 0;
}

6. References

A reference is an alias for an existing variable. Unlike pointers, references cannot be reassigned:

#include <iostream>
using namespace std;

int main() {
    int num = 10;
    int &ref = num;  // Reference to num
    
    cout << "num = " << num << endl;
    cout << "ref = " << ref << endl;
    
    ref = 20;  // Changes num
    cout << "After ref = 20:" << endl;
    cout << "num = " << num << endl;
    cout << "ref = " << ref << endl;
    
    return 0;
}

7. Pointers vs References

FeaturePointerReference
Declarationint *ptr;int &ref = var;
ReassignmentYesNo
Null valueCan be nullCannot be null
ArithmeticYesNo
MemoryTakes memoryNo extra memory

8. Function Pointers

#include <iostream>
using namespace std;

int add(int a, int b) {
    return a + b;
}

int multiply(int a, int b) {
    return a * b;
}

int main() {
    int (*funcPtr)(int, int);  // Function pointer
    
    funcPtr = add;
    cout << "Add: " << funcPtr(5, 3) << endl;
    
    funcPtr = multiply;
    cout << "Multiply: " << funcPtr(5, 3) << endl;
    
    return 0;
}

9. Smart Pointers (C++11)

Modern C++ provides smart pointers for automatic memory management:

  • unique_ptr: Exclusive ownership, automatically deleted
  • shared_ptr: Shared ownership, reference counted
  • weak_ptr: Non-owning reference to shared_ptr
#include <iostream>
#include <memory>
using namespace std;

int main() {
    // unique_ptr - automatically deleted
    unique_ptr<int> ptr(new int(10));
    cout << *ptr << endl;
    // Memory automatically freed when ptr goes out of scope
    
    // shared_ptr - reference counted
    shared_ptr<int> sptr1 = make_shared<int>(20);
    shared_ptr<int> sptr2 = sptr1;  // Both point to same memory
    cout << *sptr1 << endl;
            // Memory freed when last shared_ptr is destroyed
    
    return 0;
}

Summary

TopicKey PointsDifficulty
Basic PointersStore memory addresses, use & for address, * for dereferenceIntermediate
Pointer ArithmeticIncrement/decrement moves by size of pointed type, useful for arraysIntermediate
Dynamic Memorynew allocates, delete deallocates, must match new[] with delete[]Intermediate
ReferencesAlias for variables, must be initialized, cannot be reassignedIntermediate
Smart Pointersunique_ptr, shared_ptr, weak_ptr for automatic memory management (C++11)Advanced
Pointers vs ReferencesPointers can be null/reassigned, references are aliases, prefer references when possibleIntermediate

Frequently Asked Questions

Q1: What is the difference between a pointer and a reference?

Pointers can be null, reassigned, and use * for dereferencing. References must be initialized, cannot be reassigned, and are automatically dereferenced. References are safer (cannot be null) but less flexible. Use references for function parameters when you don't need null or reassignment, use pointers when you need these features.

Q2: What is a dangling pointer and how do I avoid it?

A dangling pointer points to memory that has been deallocated. This happens when you delete memory but still have a pointer to it, or when a pointer points to a local variable that goes out of scope. Avoid by setting pointers to nullptr after delete, ensuring pointers don't outlive the memory they point to, and using smart pointers which handle this automatically.

Q3: What is the difference between new/delete and malloc/free?

new/delete are C++ operators that call constructors/destructors and are type-safe.malloc/free are C functions that only allocate raw memory. Always use new/delete in C++ for objects, as they properly initialize and clean up. Mixing them (new with free, malloc with delete) causes undefined behavior.

Q4: When should I use smart pointers instead of raw pointers?

Use smart pointers (unique_ptr, shared_ptr) for automatic memory management. They prevent memory leaks, handle exceptions safely, and make ownership clear. Use unique_ptr for exclusive ownership, shared_ptr for shared ownership. Reserve raw pointers for non-owning references, interfacing with C code, or performance-critical code where you manage memory manually.

Q5: What is pointer arithmetic and when is it useful?

Pointer arithmetic allows adding/subtracting integers to pointers, moving by the size of the pointed type. Useful for iterating through arrays, implementing algorithms, and working with contiguous memory. For example, ptr++moves to the next element, not just the next byte. Only valid for pointers to array elements.

Q6: Can I have a pointer to a pointer? Why would I need it?

Yes, you can have pointers to pointers (int **pptr). They're useful for: dynamic 2D arrays, modifying pointer values in functions, arrays of pointers, and implementing data structures. Each level of indirection adds another layer of addressing. Be careful with multiple levels as they can become confusing.

Q7: What happens if I forget to delete dynamically allocated memory?

Forgetting to delete causes a memory leak - memory is allocated but never freed, consuming system resources. In long-running programs, this can exhaust available memory. Modern operating systems reclaim memory when programs exit, but it's still bad practice. Use smart pointers or RAII (Resource Acquisition Is Initialization) to prevent leaks automatically.

Q8: What is a null pointer and how do I check for it?

A null pointer doesn't point to any valid memory address. In C++11+, use nullptr(preferred) or NULL (legacy). Check with if (ptr == nullptr)or if (!ptr). Always check pointers before dereferencing to avoid crashes. References cannot be null, which is one advantage they have over pointers.

Conclusion

Pointers are fundamental to C++ programming, providing direct memory access and enabling dynamic memory management. Understanding pointers deeply is essential for advanced programming, implementing data structures, and writing efficient code. However, they require careful management to avoid memory leaks, dangling pointers, and undefined behavior.

Modern C++ provides smart pointers (unique_ptr, shared_ptr) that automate memory management and make code safer. While learning raw pointers is important for understanding how memory works, prefer smart pointers in production code for automatic resource management. References provide a safer alternative to pointers when you don't need null values or reassignment.

Mastery of pointers, references, and memory management is crucial for becoming a proficient C++ programmer. These concepts form the foundation for understanding more advanced topics like move semantics, RAII, and efficient resource management. Practice with pointers helps develop a deep understanding of how programs interact with memory, which is valuable across all programming languages.

Related Links

🔹 Author: Dr. J. Siva Ramakrishna

🔹 Institution: Narayana Engineering College, Gudur

🔹 Last Updated: 9 January 2026