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 create a reference.

Pointers are a feature inherited from C. They are both hated and loved (both unjustly)

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

Definition of a pointer

The basic syntax to define a pointer is:

type *pointerName;

Where:

  • type is the data type to which the pointer points.
  • 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 to which the pointer points.

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

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

Assigning Addresses

To assign a memory address to a pointer, the address-of 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.

Example of Functions with Pointers

#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 allocated dynamically 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 for a dynamic array is allocated and freed.

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 of nullptr

Use nullptr instead of NULL or 0 for null pointers.

int *ptr = nullptr;

Complete Example: Dynamic Management of an Integer List

#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 release of dynamic memory.