Punteros, referencias y punteros a arrays. Utilización en las funciones.
Estos tres conceptos están sumamente ligados entre si, y por ende con dirección de memoria. Ya vimos que un puntero es una variable que contiene la dirección en memoria de otra variable, ahora veremos que uso se le puede dar en las funciones.
Los punteros se utilizan en funciones por varios motivos:
Manipular completamente las variables que se pasan como argumento a la función, permitiendo que los cambios en dichas variables se vean reflejados fuera de ella.
Recuperar de una función más de un valor.
Optimizar el procesamiento.
Retornar referencias
Este ejemplo cumple con los tres primeros motivos mencionados (Referencias se ve en breve).
void intercambiar(int *a, int *b)
{
int aux;
aux = *a;
*a = *b;
*b = aux;
}
La función intercambia dos valores. Para ello solicita dos punteros a enteros, utilizando para acceder a estos valores, el operador de indirección (*).
La llamada a la misma se realiza utilizando el operador de referencia (&).
int a = 1, b = 3;
intercambiar(&a, &b);
//como resultado la funcion intercambia los valores, a = 3 y b = 1
Si lo que queremos es retornar un puntero deberemos definir la función de otra forma, así que démosle además una nueva funcionalidad, retornando el puntero al mayor de los dos números de ésta manera.
int* intercambiar(int *a, int *b)
{
int aux;
aux = *a;
*a = *b;
*b = aux;
return (*a > *b)? a: b;
}
int a = 1, b = 3, *c;
c = intercambiar(&a,&b);
ShowMessage("El mayor es: " + IntToStr(*c)); // que esta en a y en c
Las referencias son seudónimos o alias que se aplican a otra entidad del mismo tipo. Para declarar una referencia se coloca & después del tipo de variable y antes del identificador de la misma. Las variables de referencias necesitan inicialización y éste valor (variable o literal) no podrá ser modificado.
int a; // supongamos direccion 0x2740
a = 5; // se asigna el valor 5 a la variable
int& b = a; // creamos la referencia b a la variable a
Tanto a como b están en la misma dirección de memoria, de tal manera que al modificar una de ellas, se modifica la otra. Siguiendo el ejemplo la dirección de b es 0x2740 (la misma que a).
b = 7; // tanto a como b ahora almacenan 7
a = 0; // tanto a como b ahora almacenan 0
Por lo tanto, las referencias, se pueden pensar como punteros a una dirección de memoria fija.
Siguiendo con el ejemplo anterior, pero con referencias:
void intercambiar(int &a, int &b)
{
int aux;
aux = a;
a = b;
b = aux;
}
int a = 1, b = 3;
intercambiar(a, b);
//como resultado la funcion intercambia los valores, a = 3 y b = 1
Tanto el código con punteros como éste ultimo con referencias arrojan el mismo resultado, con la ventaja que el último permite no utilizar el operador de indirección, además en C++ las referencias son muy utilizadas para pasar argumentos a funciones (y como valores de retorno), no sólo para poderlos modificar dentro de la función, sino también por motivos de eficiencia, pues es mucho más rápido pasar un puntero o una referencia de una variable que una copia del valor de esa variable. Si además la variable es una estructura, las ventajas de eficiencia son todavía mucho más notables.
No se debe confundir el uso de (&) en la declaración de una referencia con el operador dirección (&), de la misma forma que no se debe confundir el carácter (*) en la declaración de un puntero, con el operador indirección (*).
El que una función tenga como valor de retorno una variable tipo referencia permite utilizarla de una manera un poco singular. Considérese el siguiente ejemplo:
int& intercambiar(int &a, int &b)
{
int aux;
aux = a;
a = b;
b = aux;
return (a > b)? a: b;
}
Esto permite utilizarla, por ejemplo, del siguiente modo:
int a = 1, b = 3;
intercambiar(a,b) = 0;
Ésta es una forma un poco extraña de utilizar una función: la llamada está a la izquierda del operador de asignación, en vez de aparecer a la derecha en una expresión aritmética o de otro tipo.
El resultado de esta llamada también es un poco extraño: el valor de retorno es una referencia, esto es un alias del argumento de valor máximo. Cuando la llamada a la función se sustituye por su valor de retorno, el resultado de la sentencia anterior es que la variable pasada como argumento que tiene mayor valor se hace igual a cero. Este mismo efecto puede conseguirse mediante punteros, pero con referencias resulta mucho más sencillo.