C++ Call by Reference Using Pointers


Introduction

In C++, there are two primary ways to pass arguments to a function: call by value and call by reference. In call by reference, the function works directly with the original variables, rather than copies, which allows modifications to be reflected outside the function. While references are commonly used for call by reference, pointers can also be used for this purpose.

Using pointers for call by reference is particularly useful when you need to:

  • Pass large structures or arrays to functions without copying.
  • Modify multiple variables inside a function.
  • Work with dynamic memory allocation.

In this guide, we'll explain how pointers can be used to pass arguments by reference in C++.


1. What is Call by Reference Using Pointers?

In call by reference, rather than passing the value of the argument to the function, we pass the memory address of the variable. This allows the function to modify the actual variable, not just a copy.

When you use pointers for call by reference, you pass the pointer to the function, which contains the memory address of the variable you want to modify.

Syntax:

void function_name(data_type* pointer) {
    // Function code that uses the pointer to modify the original variable
}
  • The function parameter is a pointer (data_type* pointer), which points to the original variable passed by the caller.

2. Call by Reference Using Pointers: Example

Let's take a look at a simple example to demonstrate how to pass arguments by reference using pointers.

Example 1: Swapping Two Numbers Using Pointers

#include <iostream>
using namespace std;

// Function to swap two numbers using pointers
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int x = 5, y = 10;
    cout << "Before swap: x = " << x << ", y = " << y << endl;

    // Pass the memory address of x and y to the function
    swap(&x, &y);  // Pass pointers to x and y

    cout << "After swap: x = " << x << ", y = " << y << endl;

    return 0;
}

Output:

Before swap: x = 5, y = 10
After swap: x = 10, y = 5

Explanation:

  • The swap function accepts pointers as arguments (int* a, int* b).
  • In the main function, we pass the addresses of x and y to swap using the & operator.
  • Inside the swap function, we dereference the pointers (*a, *b) to access the values at those memory addresses, allowing us to modify the original variables x and y.

3. Call by Reference Using Pointers: Modifying Arrays

Pointers can also be used to modify arrays in a similar way. Arrays are inherently passed by reference in C++, but using pointers explicitly can help you understand how data is passed and modified.

Example 2: Modifying an Array Using Pointers

#include <iostream>
using namespace std;

// Function to modify array elements using pointers
void modifyArray(int* arr, int size) {
    for (int i = 0; i < size; i++) {
        *(arr + i) = *(arr + i) * 2;  // Double each element
    }
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);

    cout << "Before modification: ";
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    // Pass the array (actually a pointer to the first element)
    modifyArray(arr, size);

    cout << "After modification: ";
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    return 0;
}

Output:

Before modification: 1 2 3 4 5
After modification: 2 4 6 8 10

Explanation:

  • The modifyArray function accepts a pointer int* arr that points to the first element of the array.
  • We use pointer arithmetic (*(arr + i)) to modify each element of the array.
  • Since the array is passed by reference (as a pointer), the changes made inside the function reflect in the original array.

4. Advantages of Using Pointers for Call by Reference

  • Efficient Memory Usage: Using pointers avoids copying large data structures, arrays, or objects to the function, thus saving memory.
  • Modifying Multiple Values: You can modify multiple variables or array elements by passing pointers to them.
  • Dynamic Memory Management: Pointers allow for dynamic memory allocation, enabling flexibility when dealing with memory during runtime.

5. Call by Reference Using Pointers: Working with Structures

You can also pass structures to functions by reference using pointers, allowing you to modify the structure’s members.

Example 3: Modifying a Structure Using Pointers

#include <iostream>
using namespace std;

// Define a structure
struct Person {
    string name;
    int age;
};

// Function to modify structure members using pointers
void modifyPerson(Person* p) {
    p->name = "John Doe";  // Modify name using pointer
    p->age = 30;           // Modify age using pointer
}

int main() {
    Person p1 = {"Alice", 25};
    
    cout << "Before modification: " << p1.name << ", " << p1.age << endl;
    
    // Pass the pointer to the structure
    modifyPerson(&p1);
    
    cout << "After modification: " << p1.name << ", " << p1.age << endl;

    return 0;
}

Output:

Before modification: Alice, 25
After modification: John Doe, 30

Explanation:

  • The modifyPerson function accepts a pointer to a Person structure (Person* p).
  • Inside the function, the -> operator is used to modify the members of the structure.
  • The original structure p1 is modified because we passed its address to the function.

6. Pointers and Call by Reference with Dynamic Memory

Pointers are especially useful when working with dynamic memory allocation (using new and delete). You can modify dynamically allocated memory in the same way as with stack-allocated variables.

Example 4: Modifying Dynamic Memory Using Pointers

#include <iostream>
using namespace std;

void allocateAndModify(int* ptr) {
    *ptr = 100;  // Modify the value using pointer
}

int main() {
    int* p = new int;  // Dynamically allocate memory for one integer

    cout << "Before modification: " << *p << endl;  // Uninitialized value

    // Modify the dynamically allocated memory
    allocateAndModify(p);

    cout << "After modification: " << *p << endl;  // Value should be 100

    delete p;  // Free the allocated memory
    return 0;
}

Output:

Before modification: 0
After modification: 100

Explanation:

  • We dynamically allocate memory for an integer using new int.
  • The allocateAndModify function modifies the dynamically allocated value using the pointer.
  • After the modification, the value is printed, and we free the memory with delete.