Los punteros (o apuntadores) son variables que se utilizan para almacenar direcciones de memoria, puntualmente las direcciones de memoria que fueron asignadas a variables convencionales en las que se almacenan datos de distinto tipo. Vale la pena entonces recordar que a todas las variables en C++ se les asigna un espacio de memoria en el cual se va almacenar el valor que se le asigne en algún punto de la aplicación a esa variable, el tamaño de dicho espacio va depender del tipo de dato que se pretende almacenar en la variable, del compilador y de la arquitectura del procesador. Cada uno de los espacios de memoria cuenta con una dirección para identificarlo, esta dirección es por lo general un número en representación hexadecimal. Es precisamente ese número correspondiente a la dirección lo que se almacena en un puntero.
Los punteros se usan ampliamente en C y
C++ para tres propósitos principales:
·
para asignar nuevos objetos en el
montón,
·
para pasar funciones a otras funciones
· para recorrer en iteración los elementos de matrices u otras estructuras de datos.
Los punteros permiten
simular el paso por referencia, crear y manipular estructuras dinámicas de
datos, tales como listas enlazadas, pilas, colas y árboles. Generalmente las
variables contienen valores específicos. Para obtener o modificar el valor de
la variable a la que apuntan se utiliza el operador de indirección. Los
punteros, al ser variables deben ser declaradas como punteros antes de ser
utilizadas.
Sintaxis
ID = 8;ptrID = &ID; // puntero a IDptrID es un puntero a int, mientras que
la variable ID es solo una variable del tipo int. Todo puntero debe ser
precedido por un asterisco (*) en la declaración.
Se puede declarar más de un puntero en
la misma sentencia. En el ejemplo que sigue se ve la declaración de dos
punteros a int.
C++ moderno proporciona punteros
inteligentes para asignar objetos, iteradores para recorrer estructuras de datos y expresiones
lambda para pasar funciones. Al usar estas instalaciones
de lenguaje y biblioteca en lugar de punteros sin formato, hará que el programa
sea más seguro, más fácil de depurar y más sencillo de entender y mantener.
Ejemplo de punteros
Muy
bien, ya hemos creado y usado nuestro primer puntero ¿Notaste el uso del asterisco y del ampersand? espero que sí y además de eso hay otros detalles que
debemos considerar, veamos:
Detalles al crear y usar punteros en C++
- El tipo de dato del apuntador debe coincidir con
el de la variable cuya posición en memoria apuntan. En el ejemplo vemos
que tanto variable como apuntador son enteros.
- Siempre que queremos usar el apuntador debemos
anteponer el asterisco (*) para indicar que usaremos el valor en la posición de
memoria apuntada.
- De no usar el asterisco el comportamiento sería
impredecible. Estaremos haciendo uso de la dirección de memoria más no del
valor almacenado en ésta.
- Después de usar un puntero, especialmente si
trabajamos con arreglos o matrices, es MUY recomendable liberar la memoria
utilizada con la función delete (tal como en el ejemplo)
- Un puntero o apuntador puede ser de cualquier
tipo de dato, inclusive los podemos usar con tipos complejos.
OPERADORES
Ya
que sabemos algunos trucos y detalles sobre los apuntadores en C++, vamos a
definir formalmente la utilidad del operador & y del asterisco.
Los punteros y el ampersand
El ampersand es un operador de C++ y es comúnmente utilizado
para los punteros. Este operador nos permite obtener la dirección de memoria de
una variable cualquiera y es justo esto (la dirección en memoria) lo que
utilizan los punteros para referenciar valores.
Los apuntadores y el asterisco
El asterisco es, por decirlo de alguna forma, el operador por excelencia de los punteros. SU utilidad radica en que si el valor de dicho apuntador corresponde a una dirección de memoria, el asterisco nos permite resolverla y acceder al valor almacenado allí. Viéndolo desde otro enfoque, un apuntador es únicamente una dirección de memoria (un número) y el asterisco es el que hace la magia de obtener el valor referenciado por dicha dirección.
En otras palabras existen
dos operadores a tener en cuenta cuando trabajamos con punteros. El operador
de dirección (&) que devuelve la dirección de memoria de su
operando y el operador de indirección (*) que devuelve un
alias para el objeto al cual apunta el operando del puntero.
En el siguiente ejemplo vemos como se
inicializa una variable X con el valor 15. Luego se crea un puntero a int y por
último el puntero pasa a apuntar a la variable X. Esto es, ptrX es un puntero a
X.
int *ptrX;ptrX = &X;
DECLARACIÓN DE PUNTEROS
Declaraciones
Se
puede declarar un puntero para almacenar la dirección de memoria
correspondiente a la variable var,
es decir, se puede "apuntar" un puntero a la variable var.
Para declarar un puntero se utiliza la sintaxis para declaración de variables:
calificadores opcionales, modificadores opcionales, tipo de dato obligatorio y
un identifador para el puntero que también es obligatorio. El tipo de dato del
puntero debe ser obligatoriamente el mismo tipo de dato de la variable a la que
se pretende apuntar, es decir, si se requiere almacenar la dirección en memoria
de una variable de tipo int,
entonces el tipo de dato del puntero también debe ser int.
Un puntero se distingue de otras variables porque en su declaración se utiliza
el operador * luego
del tipo de dato y antes del identificador del puntero. Observe a continuación
la declaración de varios punteros:
int *puntero_a_int;
float *puntero_a_float;
ClaseA
*puntero_a_objeto_claseA;
Para
apuntar un puntero a una variable se utilizan el operador de asignación =,
el operador & y
la variable a la que se quiere apuntar. Con el operador & se
obtiene la dirección de la variable y se le asigna al puntero mediante el
operador de asignación =.
Para
declarar un puntero se le debe informar a C que es lo que uno desea
almacenar en memoria, por lo tanto se le informa el tipo de lo almacenado,
por ejemplo:
§ char
*p; (puntero a char)
§ int *p;
(puntero a int)
§ float *p; (puntero a float)
La forma general de la declaración de un puntero es tipo *variable;
OPERACIONES CON PUNTEROS
Un puntero es un tipo de dato similar a un entero, y
hay un conjunto de operaciones definidas para punteros:
- La suma
o resta de un entero produce una nueva localización de memoria.
- Se
pueden comparar punteros, utilizando expresiones lógicas, para ver si
están apuntando o no a la misma dirección de memoria.
- La
resta de dos punteros da como resultado el número de variables entre las
dos direcciones.
Veamos un ejemplo de utilización de punteros:
#include
<iostream.h>
main()
{
int vector[3];
int* princPunt = vector;
int* finPunt = &vector[2];
vector[2] =
15;
cout << *(princPunt+2) << '\t' << *finPunt
<<'\n';
if (princPunt ==
finPunt)
cout << " Esto no puede suceder "
<< '\n';
cout
<< "Numero de elementos \t" <<finPunt-princPunt <<
'\n';
}
El resultado de la ejecución de este programa es:
15 15
Numero de elementos 2
Veamos cómo trabaja este programa:
- princPunt
es la dirección del primer elemento de vector, y finPunt la dirección del
último elemento. int princPunt = vector; es una combinación de declaración
y definición.
- La
expresión *(princPunt+2) incrementa el valor del puntero princPunt en dos
y devuelve el número guardado en esa localización, es decir, apunta a la
tercera localización de memoria y su valor es 15.
- Se
pueden utilizar también enteros en formato hexadecimal. Así,
cout
<< *(princPunt + 17 )
y
cout
<< *(princPunt + 0x11 )
producen la misma salida.
- La
expresión princPunt == finPunt comprueba si los dos punteros son iguales.
Esto sólo puede ser verdad si los dos punteros apuntan a la misma
variable.
Siempre que se realiza una operación aritmética sobre
un puntero, sumando o restando un entero, el puntero se incrementa o decrementa
un número apropiado de sitios tal que el nuevo valor apunta a la variable que
está n elementos (no n bytes) antes o después que el dado. De la misma forma,
al restar dos punteros se obtiene el número de objetos entre las dos localizaciones.
Finalmente, dos punteros son iguales si y sólo si apuntan a la misma variable
(el valor de las direcciones es el mismo). No son necesariamente iguales si sus
valores indirectos son los mismos, ya que estas variables podrían estar en
diferentes localizaciones de memoria.
VÍDEOS DE APOYO
No hay comentarios.:
Publicar un comentario