Punteros en C+

Punteros en C++

Punteros en C++

Todos los lenguajes de programación tienen una característica particular que los distingue del resto, algunos tienen más marcada su “personalidad” que otros. Es el caso de C++ y los punteros. Se puede señalar que C++ tiene el alcance y potencia que tiene por la implementación de los punteros. Finalmente no debemos olvidar que son herencia del lenguaje C.

Además hay que señalar que el tema de los punteros siempre es causa de conflicto y, porque no decirlo, desesperación de programadores, más si son nuevos o solo han utilizado lenguales de alto nivel. Solo puedo decir que sí, cuesta trabajo asimilar con claridad el uso de los punteros, pero las horas o días que dediques a esto, valdrán la pena.

La tercera idea que hay que mencionar es que los punteros son los que en gran medida le dan la potencia que tiene a C++, son los que hacen que C++ llegue a donde los otros lenguajes de alto nivel no pueden.

¿Para qué se utilizan los punteros?

En C++ utilizamos los punteros para acceder a la memoria y manipular las direcciones de memoria.

Direcciones de memoria en C++

Para entender a los punteros primero debes conocer cómo se almacenan los datos en la memoria de la computadora.

Cada que defines una variable en tu programa es asignada en una ubicación física en la memoria de la computadora. El valor que almacena dicha variable es almacenado en la ubicación asignada.

Para conocer en donde están almacenados los datos, C++ cuenta con el operador & (ampersand). En punteros el operador & se denomina operador de referencia. El operador & te indica la dirección ocupada por una variable.

En algunos textos el operador & recibe el nombre de operador de dirección

Sintaxis para obtener una dirección de memoria

&Variable

en donde,

& es el operador de referencia, se de poner siempre antes del nombre de la variable
Variable, variable de la cual deseamos obtener la dirección en memoria.

Si edad es una variable, &edad devolverá la dirección de esta variable.

// eb50_punteros1.cpp
// Compilado en https://www.onlinegdb.com/online_c++_compiler

#include <iostream>

using namespace std;

int main()
 {
 int var1 = 3;
 int var2 = -98;
 int var3 = 25;
 
 cout << &var1 << endl;
 cout << &var2 << endl;
 cout << &var3 << endl;

return 0;
 }

Al ejecutar el código obtendremos una salida similar a la siguente, (considera que en tu sistema podrá aparecer otra información).

0x7ffe788e5764
0x7ffe788e5768 
0x7ffe788e576c

El 0x indica que las direcciones mostradas están en formato hexadecimal.

Observa que entre cada variable hay una diferencia de 4 bytes, esto se debe a que en sistemas de 64 bits una variable entera ocupa 4 bytes.

Punteros a variables

C++ te da la posibilidad de manipular el contenido de las variables en memoria de forma directa. Puedes asignar o desasignar cualquier espacio de memoria como desees. Esto se realiza utilizando punteros a variables.

Los punteros a variables son variables que apuntan a una dirección específica en la memoria apuntada por otra variable.

Sintaxis para declarar un puntero a una variable

tipo *Variable;
o,
tipo* Variable;

en donde,

tipo, tipo de dato válido en C++
*, obligatorio, el asterisco es el operador de desreferencia y puede ser leído como “el valor apuntado por
Variable, Nombre de la variable.

Por ejemplo,

int *p;
o
int* p;

Define un puntero a la variable p, y tiene la dirección de la memoria de p

Operador de referencia (&) y Operador de desrefrencia (*)

Como se mencionó anteriormente, el operador de referencia nos da la dirección de una variable.

Para obtener el valor almacenado en una dirección de memoria, utilizamos el operador de desreferencia (*)

Por ejemplo si la variable numero se encuentra almacenada en la dirección &123, y ésta contiene el valor 5.

El operador de referencia (&) te dará el valor &123, mientras el operador de desreferencia (*) devuelve el valor 5

Nota: El signo (*) utilizado en la declaración del puntero C ++ no es el puntero de desreferencia. Es solo una notación similar que crea un puntero.

Declaración de varios punteros

En la siguiente sentencia,

int p1, p2, p3;

las variables p1, p2, p3; son de tipo int. Tal como aprendimos en el apartado de declaración de variables.

Ahora considera,

int* p1, p2, p3;

De acuerdo a lo que sabemos podemos suponer que p1, p2, p3 son 3 variables puntero. Pero no es así, en la sentencia anterior tenemos que p1 es un puntero a un int, pero p2 y p3 son de tipo int.

Si queremos que las 3 variables sean puntero, es necesario declararlo de forma explícita:

int* p1, *p2, *p3;

o bien,

int* p1; //equivalente a int *p3;
int* p2; //equivalente a int *p3;
int* p3; //equivalente a int *p3;

puedes comprobar esto fácilmente con un pequeño programa,

 // eb53_punteros4.cpp
 // Este programa forma parte del tutorial de introducción al lenguaje C++
 // http://ehack.info/leguaje-c-introduccion/
 // Se ilustra la declaración de punteros en la misma línea
 // 2018, Por http://about.me/carlosgbr
 // Versión 1
 // Compilado en https://www.onlinegdb.com/online_c++_compiler

#include <iostream>

using namespace std;

int main()
 {

 // Primero compila (ejecuta) el programa como se presenta,
 // Una vez que compruebes que el programa compila, quita los comentarios de la
 // siguiente sección y vuelve a compiar. Compara el resultado.

/* int var = 50;
 int* p1, p2, p3;

 p1 = &var; // guardamos el valor de la dirección en el puntero
 p2 = &var; // devuelve el error error: invalid conversion from 'int*' to 'int' [-fpermissive]
 p3 = &var; // devuelve el error error: invalid conversion from 'int*' to 'int' [-fpermissive]
 
 */
 
 int var = 50;
 int* h1, *h2, *h3;

 h1 = &var; // guardamos el valor de la dirección en el puntero
 h2 = &var; // devuelve el error error: invalid conversion from 'int*' to 'int' [-fpermissive]
 h3 = &var; // devuelve el error error: invalid conversion from 'int*' to 'int' [-fpermissive]
 
 return 0;
 }

De este modo comprobamos fácilmente que para declarar varios punteros en la misma línea, necesitamos utilizar el operador * para cada variable.

Ejemplo. Punteros en C++

 // eb51_punteros2.cpp
 // Este programa forma parte del tutorial de introducción al lenguaje C++
 // http://ehack.info/leguaje-c-introduccion/
 // Se ilustra el uso y definición de punteros en C++.
 // Este ejemplo se adapta de https://www.programiz.com/cpp-programming/pointers
 // Versión 1
 // Compilado en https://www.onlinegdb.com/online_c++_compiler

#include <iostream>

using namespace std;

 int main()
 {
 int *pc, c;
 
 c = 5;
 cout << "Dirección de c (&c): " << &c << endl;
 cout << "Valor de (c): " << c << endl << endl;

 pc = &c; // El puntero pc almacena la dirección de memoria de la variable c
 cout << "La dirección del puntero pc almacena (pc): "<< pc << endl;
 cout << "El contenido de la dirección del puntero pc almacena (*pc): " << *pc << endl << endl;
 
 c = 11; // El contenido dentro de la dirección de memoria &c se cambia de 5 a 11.
 cout << "La dirección del puntero pc almacena (pc): " << pc << endl;
 cout << "El contenido de la dirección del puntero pc almacena (*pc): " << *pc << endl << endl;

 *pc = 2; 
 cout << "Dirección de c (&c): " << &c << endl;
 cout << "Valor de c (c): " << c << endl << endl;

 return 0;
}

Salida del programa,

 Dirección de c (&c): 0x7ffea530a34c 
 Valor de (c): 5 
 
 La dirección del puntero pc almacena (pc): 0x7ffea530a34c 
 El contenido de la dirección del puntero pc almacena (*pc): 5 
 
 La dirección del puntero pc almacena (pc): 0x7ffea530a34c 
 El contenido de la dirección del puntero pc almacena (*pc): 11 
 
 Dirección de c (&c): 0x7ffea530a34c 
 Valor de c (c): 2

Primero te muestro de forma gráfica lo que ocurre:

Asignación de Punteros
Asignación de Punteros

Explicación del programa

  • Cuando c = 5, el valor 5 se almacena en la dirección de la variable c – 0x7ffea530a34c
  • Cuando pc = &c; el puntero pc almacena la dirección de c – 0x7ffea530a34c, y la expresión (operador de desreferencia) *pc muestra el valor almacenado en esta dirección, es decir 5.
  • Cuando c = 11; debido a que la dirección del puntero pc almacenada es la misma que c – 0x7ffea530a34c, el cambio en el valor de c se ve reflejado así mismo cuando la expresión *pc es ejecutada. que ahora muestra 11.
  • Cuando *pc = 2; esto cambio el contenido almacenado en la dirección de pc – 0x7ffea530a34c. Esto es cambiado de 11 a 2. De este modo, cuando imprimimos el valor de c, el valor será 2 también.

Inicialización de punteros.

Los punteros requieren ser inicializados al igual que cualquier otra variable, de hecho es más relevante en el tema de los punteros.

La inicialización de un puntero se hace asignando 0 a un puntero.

int* h1 = 0;
char *h2 = 0;
bool *h3 = 0;

en algunos textos se propone el uso de NULL, para inicializar variables, recordemos que NULL en muchas librerías se define como 0L (0 entero largo), sin embargo se sugiere la asignación de 0 de forma directa.

Errores comunes al utilizar punteros

Supongamos que quieres que el puntero pc apunte a la dirección de c, entonces.

int c, *pc;
pc = c; // ¡Mal! pc tiene una dirección mientras c no es una dirección
*pc = &c; // ¡Mal! *pc es el valor apuntado por la dirección muestras &c es una dirección
pc = &c; // ¡Correcto! pc es una dirección y &pc es también una dirección
*pc = c; // ¡Correcto! *pc es el valor apuntado por la dirección y, c es así mismo su valor

En ambos casos, el puntero pc no está apuntando a la dirección de c

¿Confundido con los punteros?

Bueno, no es para menos, si nunca los has usado o estudiado lo anormal sería que no tuvieras dudas. A continuación te presento una analogía y otro ejemplo con la intención de dejar más claro el concepto.

Si tu formación es de sistemas, ingenieril o simplemente tienes curiosidad, te sugiero ampliamente que leas el excelente articulo de C con clase, Punteros, complementa muy bien esta lección y te presenta algunos temas avanzados. En el tema de punteros mejor que nunca es que mientras más información tengas, mejor.

Llamadas por referencia.

  • Supongamos que tenemos una taza llamada A que tiene café y la taza B tiene té.
  • La tarea que deseas realizar es, pasar el té a la taza A y el café a la B. ¿Cómo lo haces?Nota: No tienes una taza vacía para hacer un vertido intermedio.
  • La respuesta es simple, puedes cambiar la etiqueta A a B y B a A. De este modo ahora tenemos té en la taza A y café en la taza B.

Aquí la taza es la variable, las etiquetas A y B son direcciones de memoria, el café y el té son los datos almacenados en la variable, el puntero eres tú (tú eres quien realiza el cambio de etiquetas en las tazas)

Así es como funcionan los punteros.

Ejemplo

// eb52_punteros3.cpp
 // Este programa forma parte del tutorial de introducción al lenguaje C++
 // http://ehack.info/leguaje-c-introduccion/
 // Se ilustra la manipulación de variables con punteros.
 // 2018, Por http://about.me/carlosgbr
 // Versión 1
 // Compilado en https://www.onlinegdb.com/online_c++_compiler

#include <iostream>
using namespace std;

int main()
 {
 int var = 50; // definimos una variable "normal"
 int *p; // definimos *p como puntero a un entero
 p = &var; // guardamos el valor de la dirección en el puntero
 cout << var << endl;
 // Muestra 50 (el valor de var)
 cout << p << endl;
 // muestra 0x7fff0e40086c (la dirección de memoria de var)
 cout << *p << endl;
 /* Muestra 50 (el valor de la variable 
 almacenada en el puntero) */
 *p = 100; 
 /* cambiaos el valor almacenado dentro de la 
 variable con la ayuda del puntero */
 cout << *p << endl;
 /* Muestra 100 (el valor de la variable
 almacenada en el puntero p) */
 cout << var << endl;
 /* Muestra 100. (el nuevo valor de var que fue asignado se debió a *p=100) */

return 0;
 }

Como notas complementarias al programa anterior considera:

&var - obtiene la dirección de var

p = &var; - podemos hacer esta asignación debido a que p es de tipo puntero.

cout << p; - muestra la dirección almacenada en p,

cout << *p; - recupera el valor almacenado en la dirección (el operador de desreferencia * es quien realiza esta recuperación)

*p = 100; - asigna 100 a la dirección apuntada por p NOTA: no puedes asignar p = 100; debido a que p es puntero y debe almacenar forzosamente una dirección.

Conclusión

El uso de punteros ocasiona opiniones encontradas siempre, lo único que puedo decir a título personal es que no es tan críptico como parece, pero tampoco tan simple como algunos refieren. Los punteros requieren abstracción, paciencia y sobre todo, práctica.

Ésta es una primer aproximación a los punteros, normalmente en los textos se aborda a continuación los punteros a Arrays, a funciones y objetos. En nuestro caso primero abordaremos un último tema “core” antes de realmente empezar a explorar la potencia de C++ y sus librerías: las funciones.


¿Deseas aprender BIEN Seguridad Informática “desde el principio”? 

Aplicación de medidas para la implantación de la L.O.P.D. en las empresas

Obtendrás información ampliada y más recursos en comparación con el material que ofrecemos de forma gratuita, y material adicional, visita https://ehack.mx/portfolio-view/material-de-estudio-ceh-online/ para más información o ecríbenos a ceh@ehack.mx

Ethical hack
Ethical hack

 Fuente Imágenes:

Referencias:

  • (1) La columna vertebral de este artículo se escribió a partir de la publicación de la columna Learn C++ de Programiz. Se encuentra en trámite la autorización para a reproducción de este documento.
  • Se tomaron algunas ideas a partir de comentarios publicados en los foros deLearnC de SoloLearn

Código fuente:

  • El código fuente de toda la serie lo puedes descargar en nuestro repositorio en github busca los programas con el nombre del encabezado de cada programa.

Licencia Creative Commons
    Punteros en C++ por Roberto C. González se distribuye bajo una Licencia Creative Commons Atribución-NoComercial-CompartirIgual 4.0 Internacional.
    Basada en una obra en http://ehack.info/leguaje-c-introduccion/
    Permisos que vayan más allá de lo cubierto por esta licencia pueden encontrarse en https://about.me/carlosgbr.
Comentarios de Facebook

Leave a Reply

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.