no entiendo esta parte de un código que vi:
int *a;
int &b = *a;
Yo me pregunto:
- ¿Por qué funciona ese código si el operador ampersand (&) sirve para indicar la dirección de memoria?
Gracias de antemano.
no entiendo esta parte de un código que vi:
int *a;
int &b = *a;
Yo me pregunto:
Gracias de antemano.
¿Por qué el operador ampersand (&) funciona cuando se declara una variable?
Funciona porque el ampersand también sirve para declarar referencias en C++ (en C no).
En este caso, el identificador b
es una referencia y esto quiere decir que b
siempre se va a referir a la misma dirección de memoria que tenga guardado el puntero a
.
Para que se entienda mejor, miremos el siguiente ejemplo:
#include <iostream>
int main(void)
{
int x = 2;
int *a = &x;
int &b = *a;
b = 11;
std::cout << x;
return 0;
}
Asumamos que la dirección de x
es 0x4
. Entonces el puntero a
tendrá guardada la dirección 0x4
.
Luego en esta línea:
int &b = *a;
Se le dice al compilador: Haz que b
sea un alias de la dirección 0x4
Entonces cada vez que le intentemos asignar algo a b
:
b = 11;
En realidad estaremos modificando la variable x
, ya que, b
es un simple alias de la dirección de x
.
Esa es la razón del porque en pantalla muestra 11
y no 2
.
Conclusión:
b
es simplemente una manera de nombrar a la dirección de x
. Una analogía sería: Sí la persona A
se llama Jorge Román Lopez y le asignamos un apodo (o alias) denominado pochi
, entonces, ahora nos referimos a esa persona A
por medio de su apodo.
El signo &
, cuyo nombre en español es et, es un signo con múltiples significados en c++, el que mencionas es sólo uno de ellos:
int *a;
int &b = *a;
Ahí, el et antes de b
no está obteniendo la dirección de memoria de b
si no que está diciendo que el tipo de b
es referencia a entero:
int &b
// \~/ ^
// | |
// | \____ Referencia...
// \_____________________ a entero.
De la misma manera que int *a
no nos está multiplicando a
e int
si no que dice que el tipo de a
es puntero a entero:
int *a
// \~/ ^
// | |
// | \____ Puntero...
// \__________________ a entero.
Puedes conocer las diferencias entre puntero (*
) y referencia (&
), consultando este hilo.
Para que la respuesta sea más completa, vale la pena destacar otros usos de et en C++:
Et como referencia. Lo podemos encontrar declarando variables o parámetros:
int *a;
int &b = *a;
void funcion(int ¶metro);
Es el caso que ya se ha mencionado, en declaraciones de variables y parámetros el et nos crea referencias al tipo declarado.
Et como referencia del lado derecho. Lo podemos encontrar declarando variables o parámetros:
int &&a = 42;
void funcion(int &¶metro);
No debe ser confundido con el operador lógico AND (&&
). En este caso declara una referencia a valor del lado derecho, como el nombre es muy confuso la llamaremos referencia a valor temporal, este tipo de referencias sólo pueden apuntar a valores temporales:
funcion(666); // Correcto, 666 es temporal.
funcion(a); // Incorrecto, a es una variable no un valor temporal.
Dado que funcion
sólo puede recibir referencias a valores temporales enteros (int &&
), si le pasamos una variable falla pero funciona con un literal entero1.
Et como en la declaración de función miembro. Lo podemos encontrar declarando funciones miembro:
struct S {
void funcion() & { std::cout << "Funcion normal\n"; }
void funcion() && { std::cout << "Funcion sobre objeto temporal\n"; }
};
Si la instancia de S
usada es temporal, se llamará a la versión de funcion
de objetos temporales (la que tiene el doble et &&
) en caso contrario la otra:
S s;
s.funcion(); // Imprime 'Funcion normal'
S{}.funcion(); // Imprime 'Funcion sobre objeto temporal'
Et como AND binario. Lo podemos encontrar operando sobre dos variables:
int A = 0b101010;
int B = 0b011100;
int C = A & B;
En este caso et está operando binariamente las variables A
y B
, esto significa que está aplicando el AND a todos los bits de los operandos, lo que resultará en el valor ocho (0b0010000
).
Et como AND lógico. Lo podemos encontrar operando sobre dos variables o expresiones:
bool maldicion = es_martes() && es_dia(13);
bool apocalipsis = maldicion && hay_pandemia();
En este caso et tiene la función de AND lógico, que operará sobre las expresiones lógicas siguiendo la álgebra de Boole.
1Consulta este hilo para saber lo que es un literal.
¿Por qué funciona ese código si el operador ampersand (&) sirve para indicar la dirección de memoria?
Se trata de una referencia
Una variable referencia como lvalue
, es una variable que almacena un espacio de memoria. No se deben confundir con los punteros, los punteros apuntan a una dirección de memoria o hasta una dirección nula. Los espacio en memoria que almacenas en una referencia, no puede ser una dirección nula (NULL
).
Se puede decir que una referencia es como un apuntador constante ya que
error: expression is not assignable
error: declaration of reference variable requires an initializer
Pueden servir para asignarle un nuevo nombre a una variable ya existen. Debido a que al almacenar un espacio en memoria de una variable, cuando se modifique la referencia (espacio en memoria), se modificará el valor de la variable.
int var = 10;
int &ref = var;
ref = 5;
std::cout << var << std::endl; //Mostraría 5
Espero te sirva de algo.
En la primera parte:
int *a;
Lo que se hace es crear un puntero hacia una dirección de memoria, que para el caso podemos llamar una referencia a un sector de la memoria
En la segunda parte:
int &b = *a
Lo que se hace es "haz que la referencia de b sea igual al puntero a"; o para el caso a la referencia de memoria
Si imaginamos que para a, el puntero está apuntando a la dirección de memoria 0x0003 y por tanto esa es su referencia de memoria, luego decimos que la referencia de b es la misma; por lo tanto también 0x0003.
Si luego dices que a = 12 (por lo tanto el puntero apunta a donde se guarda el valor), el valor de b será el mismo pues su referencia apunta al mismo lugar que el puntero de a