Cargando...

Referencias vs punteros

Diferencias clave: nulidad, reasignación, indirección y semántica de memoria en C++.

En C++, existen dos conceptos importantes al trabajar con datos: punteros y referencias. Ambos se utilizan para “referirse” a otra variable; sin embargo, difieren en su funcionamiento, comportamiento en memoria y nivel de seguridad. En este artículo exploraremos los punteros y las referencias, sus diferencias y casos de uso con ejemplos.


1. ¿Qué es un puntero?

Un puntero es una variable especial que almacena una dirección de memoria. Los punteros permiten acceder indirectamente al valor de otra variable.


#include <iostream>
using namespace std;

int main() {
    int numero = 10;
    int *ptr = &numero; // la dirección de 'numero' se asigna a ptr

    cout << "Valor de numero: " << numero << endl;
    cout << "Valor de ptr (dirección): " << ptr << endl;
    cout << "Valor apuntado por ptr: " << *ptr << endl;

    *ptr = 20; // cambiamos el valor a través del puntero
    cout << "Nuevo valor de numero: " << numero << endl;

    return 0;
}

Aquí, *ptr (desreferenciación) accede al valor de la variable a la que el puntero apunta. Dado que los punteros pueden manipular directamente direcciones de memoria, son muy potentes — pero también peligrosos si no se usan con cuidado.


2. ¿Qué es una referencia?

Una referencia es un “alias” de otra variable. A diferencia de un puntero, no almacena una dirección, sino que comparte directamente la misma ubicación en memoria. Debe vincularse a una variable en el momento de su declaración.


#include <iostream>
using namespace std;

int main() {
    int x = 50;
    int &ref = x; // ref es una referencia a x

    cout << "x: " << x << ", ref: " << ref << endl;

    ref = 100; // cambiamos el valor de x mediante la referencia
    cout << "Nuevo valor de x: " << x << endl;

    return 0;
}

En este ejemplo, ref comparte la misma dirección de memoria que x. Por lo tanto, si uno cambia, el otro también cambia automáticamente.


3. Diferencias entre punteros y referencias

La siguiente tabla muestra las diferencias principales entre ambos:

CaracterísticaPunteroReferencia
Declaración int *p = &x; int &r = x;
¿Almacena una dirección? Sí, almacena una dirección de memoria No, está directamente vinculada a la variable
¿Puede ser NULL? Sí, puede ser nullptr No, debe referirse siempre a una variable
¿Puede reasignarse? Sí, puede apuntar a otra dirección No, una vez vinculada, no puede cambiarse
Desreferenciación Se accede con *p Se usa directamente
Gestión de memoria Manual (new/delete) Automática
Rendimiento Acceso indirecto Acceso directo (más rápido)

4. Vista en memoria

Veamos cómo se comportan los punteros y las referencias en la memoria:


int x = 10;
int *ptr = &x;
int &ref = x;

cout << "&x: " << &x << endl;
cout << "ptr: " << ptr << endl;
cout << "&ref: " << &ref << endl;

Ejemplo de disposición en memoria:


Variable | Dirección | Valor
x        | 0x61ff0c  | 10
ptr      | 0x61ff08  | 0x61ff0c
ref      | 0x61ff0c  | 10

Como se puede ver, ref utiliza la misma dirección de memoria que x, mientras que ptr tiene su propia dirección y almacena la de x.


5. Paso de punteros y referencias a funciones

Los punteros y las referencias pueden pasarse como parámetros a funciones para modificar variables externas.

Con puntero


void Incrementar(int *p) {
    (*p)++;
}

int main() {
    int n = 5;
    Incrementar(&n);
    cout << n; // 6
}

Con referencia


void Incrementar(int &r) {
    r++;
}

int main() {
    int n = 5;
    Incrementar(n);
    cout << n; // 6
}

Ambos métodos producen el mismo resultado, pero el uso de referencias es más limpio y seguro.


6. Referencias const

Si no desea que una función modifique el valor pasado por referencia, use la palabra clave const.


void Mostrar(const string &text) {
    cout << text << endl;
}

int main() {
    string mensaje = "¡C++ es genial!";
    Mostrar(mensaje);
}

Las referencias const & permiten pasar objetos grandes a funciones sin copiarlos, evitando modificaciones accidentales y mejorando el rendimiento.


7. Uso combinado de punteros y referencias

A veces los punteros y las referencias se usan juntos. Por ejemplo, se puede tener una referencia a un puntero.


#include <iostream>
using namespace std;

int main() {
    int x = 5;
    int *p = &x;
    int *&refAlPuntero = p; // referencia a puntero

    *refAlPuntero = 10;
    cout << x << endl; // 10
}

Esta estructura puede parecer compleja, pero es útil con memoria dinámica o funciones que necesitan modificar punteros.


8. Mejores casos de uso

En el C++ moderno, se recomienda usar referencias o smart pointers (como std::unique_ptr) en lugar de punteros sin control.


9. TL;DR

  • Un puntero almacena una dirección; una referencia es un alias de una variable.
  • Un puntero puede ser nullptr; una referencia no puede.
  • Un puntero puede reasignarse; una referencia solo se vincula una vez.
  • *p accede al valor apuntado; las referencias se usan directamente.
  • Las referencias const & permiten pasar objetos grandes sin copiarlos.
  • Use punteros para gestión de memoria; referencias para acceso simple y seguro.
  • Todos los ejemplos pueden ejecutarse en Visual Studio 2022 o GCC 11+.

Artículos relacionados