02. Apuntadores: conociendo los apuntadores

Publicado por

Gracias a la nota anterior, ahora contamos con un conocimiento general sobre la memoria y de cómo esta almacena información. Ya que el material de trabajo de los apuntadores es precisamente la memoria, era primordial conocer algo de ella.

En este entrega comenzaremos por fin a conocer qué son los apuntadores y la forma en que podemos crearlos, conforme vayamos avanzando iremos conociendo algunos otros detalles.

Encontrarás en esta nota:


¿Qué es un apuntador?

En términos generales, podemos referirnos como apuntador, puntero o pointer a una variable que almacene una dirección de memoria; tan sencillo como eso. El apuntador nos permitirá guardar la dirección de memoria donde se localiza alguna otra variable o constante.

Normalmente solo necesitamos el nombre de la variable para poder acceder a su valor; siendo así, ¿para qué molestarnos en conocer la dirección de dónde se encuentra? Ya lo iremos viendo durante la serie.


¿Cómo se declara un apuntador?

No es nada difícil declarar un apuntador, prácticamente es la misma sintaxis que cuando declaramos una variable cualquiera, la única diferencia es que debemos agregar un símbolo extra. El símbolo utilizado para esto es el asterisco (*). Este caracter debe residir entre el tipo de dato de nuestra variable y el nombre de esta:

int* num;

¡Listo! Hemos creado nuestro apuntador. Cabe decir que no importa el número de espacios que coloques antes y/o después del asterisco, la declaración será correcta independientemente de esto. Aquí unos ejemplos:

int * num;
int *num;
int*num;

A pesar de lo que se acaba de expresar, existe un estilo muy común donde el asterisco se encuentra justo antes del identificador y separado del tipo de dato por un espacio:

int *num;

Es importante decir que no existe una forma “correcta” de declarar un apuntador, todo recae en la preferencia del programador. No obstante, siempre es bueno elegir un estilo y apegarnos a él para que haya consistencia en el código que estemos trabajando.

Acertijo

Seguro recuerdas que si tenías varias variables de un mismo tipo, estas podían declararse en una misma línea colocando una única vez el tipo de dato y enseguida identificadores separados por comas. Atendiendo a lo anterior, ¿cuál de las dos opciones siguientes crees que sería la correcta al momento de declarar varios apuntadores?

Opción A

Opción B

Es común llegar a pensar que habría que escribir una única vez el tipo de dato y el asterisco para que todos los identificadores que le sigan sean considerados apuntadores, pero no es así. Como comentamos, lo que hace la diferencia entre un apuntador y una variable normal, es este operador asterisco.

Si llegamos a escribir una línea como la de la opción A, estamos diciendo que se genere un apuntador hacia una variable de tipo entero y, además, dos variables de tipo entero normales. Si queremos que todos sean apuntadores, cada identificador debe ir acompañado de su respectivo operador, tal y como se muestra en la segunda opción. Así pues, la respuesta correcta es: B.


El tipo de dato en los apuntadores

Aunque es verdad que la dirección de memoria es solo un número, esto no quiere decir que el apuntador sea de algún tipo de dato; entonces ¿por qué tengo que colocar un tipo de dato al momento de declararlo?

A diferencia de lo que ocurre con una variable común y corriente, donde el tipo de dato es necesario para saber cuanto espacio deberá reservarse en memoria, en los apuntadores ocurre otra cosa: se coloca el tipo de dato para determinar el tamaño del segmento al que el apuntador hará referencia. Por ejemplo, si estamos almacenando la dirección de una variable de tipo entero, debemos declarar un apuntador que incluya el tipo int.

Con lo que hemos visto hasta ahora, te puedo compartir una pequeña guía muy útil para el momento en que quieras leer una declaración de apuntador, lo único de que debes hacer es leer hacia atrás, como se indica en la imagen siguiente:

Leer declaración de apuntador


Conociendo la dirección de una variable

Hemos hablado suficiente de direcciones de memoria y de cómo estas son los valores que almacenan los apuntadores, siendo así, ¿cómo es que obtengo la dirección de alguna variable para poderla guardar en un apuntador?

Así como existe un operador para declarar apuntadores, existe también uno para poder obtener la dirección de una variable, este operador es el símbolo ampersand (&). Lo único que debes hacer es colocar este operador inmediatamente a la izquierda del identificador de la variable cuya dirección quieres saber.

Veamos lo anterior con un ejemplo:

// Tenemos nuestra variable de la que queremos conocer su dirección
double num = 10.0;

// Declaramos nuestro apuntador.
double *ptr;

// Obtenemos la dirección de «num» con el operador "dirección de" (el ampersand) y
// la almacenamos en el apuntador que creamos.
ptr = #

Aquí es importante notar dos cosas:

  1. Al apuntador se le coloca el tipo de dato double en su declaración puesto que la dirección que almacenará es de una variable de tipo double.
  2. Al momento de inicializar el apuntador no es necesario volver a colocar el asterisco, más adelante veremos en qué caso sí que lo requiere.

¡Y listo! De esta forma podemos obtener la dirección de cualquier variable.


Mostrando el valor de un apuntador

En ocasiones queremos saber exactamente qué dirección tiene cierta variable, para esto lo más común es que mostremos el valor en pantalla y para lograrlo tenemos dos opciones, dependiendo de si estamos usando C o C++.

Utilizando C

Haciendo uso de la función printf, cuando queremos mostrar el valor de una variable necesitamos colocar un especificador de formato de acuerdo al tipo de dato que esta tiene, por ejemplo, si vamos a mostrar una cadena de caracteres usamos %s y si vamos a mostrar un entero podemos usar %d. En el caso de los apuntadores, existe un especificador de formato especial para mostrar sus valores: %p.

// Suponiendo que hemos creado un apuntador con nombre «ptr»
printf("Valor: %p", ptr);

Utilizando C++

En este lenguaje es habitual usar la instrucción cout. Aquí la cosa es más sencilla y solo se necesita colocar el apuntador para que podamos imprimir su valor, eso sí, recuerda solo colocar el nombre apuntador sin incluir el asterisco, tal y como sucede en el apartado anterior.

// Suponemos de la misma forma que contamos con un apuntador de nombre «ptr»
std::cout << ptr << std::endl;

Es de mencionar que en ambos casos el resultado que se nos mostrará será expresado en notación hexadecimal, esto se debe a que es la notación más común en la que se suele representar y leer una dirección de memoria.


Para terminar

Lo tratado en esta nota se considera lo más básico sobre apuntadores, una vez conociendo cómo crearlos y cómo almacenar una dirección, podemos comenzar a conocer cosas más interesantes.

En la próxima entrega extenderé un poco más de lo que hemos visto hasta aquí, hablaremos sobre el concepto de NULL y de cómo realizar operaciones aritméticas con los valores que guardan los apuntadores.

Recuerda que cualquier duda que tengas puedes agregarla a los comentarios. Hasta la próxima.

Deja una respuesta

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