Language: EN

cpp-que-son-los-punteros

What are and how to use Pointers in C++

A pointer is a variable that stores the memory address of another variable. This capability allows pointers to manipulate data in memory.

Instead of directly containing a data value, a pointer contains the address where that value is located. Therefore, they are one of the simplest ways to perform a reference.

Pointers are a feature inherited from C. They are very much hated and loved (both unjustifiably)

One of C++‘s goals is to reduce or eliminate the use of pointers. However, they are still necessary.

Definition of a pointer

The basic syntax for defining a pointer is:

type *pointerName;

Where:

  • type is the data type the pointer points to.
  • pointerName is the name of the pointer.

For example,

int *ptr;

In this example, ptr is a pointer to an integer.

Dereference operator

The dereference operator * is used to access the value of the variable that the pointer points to.

int var = 10;
int *ptr = &var;

std::cout << "Value of var: " << var << std::endl;
std::cout << "Value of var using pointer: " << *ptr << std::endl;

Assignment of addresses

To assign a memory address to a pointer, the address operator & is used.

int var = 10;
int *ptr = &var;

Here, ptr stores the address of var.

Pointers and arrays

Arrays and pointers are closely related in C++. The name of an array is itself a pointer to the first element of the array.

int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr;

std::cout << "First element of the array: " << *ptr << std::endl;
std::cout << "Second element of the array: " << *(ptr + 1) << std::endl;

In this example, ptr points to the first element of the array arr.

Pointers and functions

Pointers can be used to pass large data structures to functions without the need to copy them, which is efficient in terms of memory and time.

#include <iostream>

void increment(int *ptr) {
    (*ptr)++;
}

int main() {
    int num = 10;
    increment(&num);
    std::cout << "Value of num after incrementing: " << num << std::endl;
    return 0;
}

In this example, the function increment directly modifies the value of num through a pointer.

Pointers and dynamic memory

In C++, memory can be managed dynamically using the new and delete operators.

Dynamic memory allocation

int *ptr = new int;
*ptr = 20;
std::cout << "Value stored in dynamic memory: " << *ptr << std::endl;
delete ptr;

In this example, memory for an integer is dynamically allocated and then freed.

Dynamic arrays

int *arr = new int[5];
for (int i = 0; i < 5; ++i) {
    arr[i] = i * 2;
}

for (int i = 0; i < 5; ++i) {
    std::cout << "arr[" << i << "] = " << arr[i] << std::endl;
}

delete[] arr;

Here, memory is allocated and freed for a dynamic array.

Pointers to pointers

A pointer to a pointer is a variable that contains the address of a pointer, allowing additional levels of indirection.

int var = 5;
int *ptr = &var;
int **pptr = &ptr;

std::cout << "Value of var: " << var << std::endl;
std::cout << "Value of var using ptr: " << *ptr << std::endl;
std::cout << "Value of var using pptr: " << **pptr << std::endl;

Best practices

Initialize pointers

Always initialize pointers.

int *ptr = nullptr;

Using uninitialized pointers can cause undefined behavior.


Free memory

Make sure to free any dynamically allocated memory.

int *ptr = new int;
delete ptr;

Not freeing dynamically allocated memory can result in memory leaks.


Use nullptr

Use nullptr instead of NULL or 0 for null pointers.

int *ptr = nullptr;

Complete example

Let’s look at a somewhat broader example, where we would see dynamic management of a list of integers.

#include <iostream>

class IntegerList {
private:
    int *data;
    int capacity;
    int size;

public:
    IntegerList(int cap) : capacity(cap), size(0) {
        data = new int[capacity];
    }

    ~IntegerList() {
        delete[] data;
    }

    void add(int value) {
        if (size < capacity) {
            data[size++] = value;
        } else {
            std::cerr << "List capacity exceeded" << std::endl;
        }
    }

    void display() const {
        for (int i = 0; i < size; ++i) {
            std::cout << data[i] << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    IntegerList list(10);
    list.add(1);
    list.add(2);
    list.add(3);

    std::cout << "Elements in the list: ";
    list.display();

    return 0;
}

In this example, a class IntegerList is created that manages a list of integers dynamically, demonstrating the creation, use, and freeing of dynamic memory.

It does not mean that this is the best way to solve the problem. It is an example to illustrate the use of pointers.