martes, 7 de diciembre de 2021

PUNTEROS:

 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

int *ptrID, ID;
ID = 8;
ptrID = &ID; // puntero a ID

ptrID 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.

int *ptrY, *ptrX; 

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 X = 15;
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

INTRODUCCIÓN

¿Qué es C++?   Es un lenguaje de programación de propósito general que combina distintos paradigmas o modelos de programación. El lenguaje n...