Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Ejemplo
int n; // asocia al nombre n, el tipo int y la dirección de
// alguna posición de memoria donde se almacena el
// valor de n
0x4fffd34
n
int
0x4fffd34
n 75
int
Al valor de una variable se accede por medio de su nombre. Por ejemplo, se puede imprimir el valor
de n con la sentencia
cout << n;
A la dirección de la variable se accede por medio del operador de dirección &. Por ejemplo, se pue-
de imprimir la dirección de n con la sentencia
cout << &n;
El operador de dirección «&» «opera» (se aplica) sobre el nombre de la variable para obtener sus
direcciones. Tiene precedencia de nivel 15 con el mismo nivel que el operador lógico NOT (!) y el
operador de preincremento ++. (Véase Apéndice C de la página Web del libro.)
Ejemplo 9.1
Obtener el valor y la dirección de una variable.
main()
{
int n = 75;
cout << "n = " << n << endl; // visualiza el valor de n
cout << "&n = " << &n << endl; // visualiza dirección de n
}
Ejecución
n = 45
&n = 0x4fffd34
Punteros (apuntadores) 337
Nota
0x4fffd34 es una dirección en código hexadecimal.
“0x” es el prefijo correspondiente al código hexadecimal.
9.1.1. Referencias
Una referencia es un alias de otra variable. Se declara utilizando el operador de referencia (&) que se
añade al tipo de la referencia.
Ejemplo 9.2
Utilización de referencias.
void main()
{
int n = 75;
int& r = n; // r es una referencia para n
cout << "n = " << n << ", r = " << r << endl;
}
Ejecución
n = 75, r = 75
Nota
Los dos identificadores n y r son nombres diferentes para la misma variable.
Ejemplo 9.3
Las variables n y r tienen la misma dirección de memoria
void main()
{
int n = 75;
int& r = n;
cout << "&n = " << &n << ", &r =" << &r << endl;
}
Ejecución
&n = 0x4fffd34, &r = 0x4fffd34
Regla
El carácter & tiene diferentes usos en C++: 1) cuando se utiliza como prefijo de un nombre de
una variable, devuelve la dirección de esa variable; 2) cuando se utiliza como un sufijo de un
tipo en una declaración de una variable, declara la variable como sinónimo de la variable que
se ha inicializado; y 3) cuando se utiliza como sufijo de un tipo en una declaración de paráme-
tros de una función, declara el parámetro referencia de la variable que se pasa a la función.
& se refiere a la dirección en que se almacena el valor.
338 Programación en C++. Algoritmos, estructuras de datos y objetos
n 75
Dirección de
memoria alta
1001
p 1000 p contiene el valor 100, que es la direc-
999 ción de alfa
Dirección de
memoria baja
Figura 9.1. Relaciones entre *p y el valor de p (dirección de alfa).
1
En Latinoamérica es usual emplear el término apuntador.
Punteros (apuntadores) 339
Ejemplo 9.4
void main()
{
int n = 75;
int* p = &n; // p contiene la dirección de n
cout << "n = " << n << ", &n = " << &n << ", p " << p <<
endl;
cout << "&p = " << &p << endl;
}
Ejecución
n = 75, &n = 0x4fffd34, p = 0x4fffd34
&p = 0x4fffd10
0x4fffd30 0x4fffd34
p 0x4fffd34 n 75
int* int
La variable p se denomina puntero debido a que su valor «apunta» a la posición de otro valor. Es un
puntero int cuando el valor al que apunta es de tipo int como en el ejemplo anterior.
Un operador * (que está sobrecargado) en una declaración indica que la variable declarada almace-
na una dirección de un tipo de dato especificado. La variable ptr1 almacena la dirección de un entero, la
variable ptr2 almacena la dirección, etc.
Siempre que aparezca un asterisco (*) en una definición de una variable, ésta es una variable
puntero.
pondiente. Después de la inicialización, se puede utilizar el puntero para referenciar los datos direccio-
nados. Para asignar una dirección de memoria a un puntero se utiliza el operador de referencia &. Así,
por ejemplo,
&valor
significa «la dirección de valor». Por consiguiente, el método de inicialización (iniciación), también de-
nominado estático, requiere:
• Asignar memoria (estáticamente) definiendo una variable y, a continuación, hacer que el puntero
apunte al valor de la variable.
*p = 50;
Cuando ya se ha definido un puntero, el asterisco delante de la variable puntero indica «el contenido
de» de la memoria apuntada por el puntero y será del tipo dado.
Este tipo de inicialización es estática, ya que la asignación de memoria utilizada para almacenar el
valor es fijo y no puede desaparecer. Una vez que la variable se define, el compilador establece suficien-
te memoria para almacenar un valor del tipo de dato dado. La memoria permanece reservada para esta
variable y no se puede utilizar para otra cosa durante la ejecución del programa. En otras palabras, no se
puede liberar la memoria reservada para una variable. El puntero a esa variable puede ser cambiado, pero
la cantidad de memoria reservada permanecerá.
Existe un segundo método para inicializar un puntero, es mediante asignación dinámica de memoria.
Este método utiliza los operadores new y delete, y se analizará más adelante en este capítulo.
Las dos sentencias anteriores se describen en la Figura 9.2. Si se desea imprimir el valor de edad, se
puede utilizar la siguiente sentencia cout:
memoria
direcciones
50
p_edad apunta a
edad
p_edad en 320.000
320,000
línea de memoria
Figura 9.2. p_edad contiene la dirección de edad, p_edad apunta a la variable edad.
El listado PUNTERO1.CPP muestra el concepto de creación, inicialización e indirección de una va-
riable puntero.
// PUNTERO1.CPP
#include <iostream.h>
int main()
{
char *pc; // un puntero a una variable carácter
pc = &c;
for (c = 'A'; c <= 'Z'; c++);
cout << *pc;
return 0;
}
La ejecución de este programa visualiza el alfabeto. La variable puntero pc es un puntero a una va-
riable carácter. La línea pc = &c asigna a pc la dirección de la variable c (&c). El bucle for almacena
en c las letras del alfabeto y la sentencia cout << *pc; visualiza el contenido de la variable apuntada
por pc. c y pc se refieren a la misma posición en memoria. Si la variable c, que se almacena en cual-
quier parte de la memoria, y pc, que apunta a esa misma posición, se refiere a los mismos datos, de
modo que el cambio de una variable debe afectar a la otra. pc y c se dice que son alias, debido a que
pc actúa como otro nombre de c.
342 Programación en C++. Algoritmos, estructuras de datos y objetos
pc c
Valor de dirección
del puntero 05 'A'
Direcciones 00 01 02 03 04 05 06 07
memoria
Figura 9.3. pc y c direccionan la misma posición de memoria.
Operador Propósito
Nota
Son variables punteros aquellas que apuntan a la posición en donde otra/s variable/s de pro-
grama se almacenan.
float *fp;
char c;
fp = &c; // no es válido
C++ no permite la asignación de la dirección de c a fp, ya que fp es una variable puntero que apun-
ta a datos de tipo real, float.
C++ requiere que las variables puntero direccionen realmente variables del mismo tipo de dato
que está ligado a los punteros en sus declaraciones.
se inicializa el puntero. En consecuencia, será preciso asegurarse que las variables puntero utilicen di-
recciones de memoria válida.
Existen dos tipos de punteros especiales muy utilizados en el tratamiento de sus programas: los pun-
teros void y null (nulo).
Un puntero nulo no apunta a ninguna parte —objeto válido— en particular, es decir, «un puntero
nulo no direcciona ningún dato válido en memoria». Un puntero nulo se utiliza para proporcionar a un
programa un medio de conocer cuándo un puntero apunta a una dirección válida. Para declarar un pun-
tero nulo se utiliza la macro NULL, definida en los archivos de cabecera stdef.h, stdio.h,
stdlib.h y string.h. Se debe incluir uno o más de estos archivos de cabecera antes de que se pueda
utilizar la macro NULL. Ahora bien, se puede definir NULL en la parte superior de su programa (o en un
archivo de cabecera personal) con la línea
#define NULL 0
Algunas funciones C++ también devuelven el valor NULL si se encuentra un error. Se puede añadir
una prueba o test comparando el puntero con NULL:
if (p == NULL) ...
o bien
if (p != NULL) ...
Nunca se utiliza un puntero nulo para referenciar un valor. Como antes se ha comentado, los punteros
nulos se utilizan en un test condicional para determinar si un puntero se ha inicializado. En el ejemplo
if (ptr)
cout << "Valor de la variable apuntada por ptr es: "
<< *ptr << "\n";
El puntero ptr puede direccionar cualquier posición en memoria, pero el puntero no está unido a un
tipo de dato específico. De modo similar, los punteros void pueden direccionar una variable float, una
char, o una posición arbitraria o una cadena.
Nota
No confundir punteros void y null. Un puntero nulo no direcciona ningún dato válido. Un pun-
tero void direcciona datos de un tipo no especificado. Un puntero void se puede igualar a nulo
si no se direcciona ningún dato válido. Nulo es un valor; void es un tipo de dato.
344 Programación en C++. Algoritmos, estructuras de datos y objetos
ptr1 y ptr5 son punteros. ptr1 apunta a la variable valor_e de tipo int. ptr5 contiene la dirección
de ptr1. En la Figura 9.4 se muestran las declaraciones anteriores.
8000
valor_e = 95;
*ptr1 = 105; // Asigna 105 a valor_e
**ptr5 = 99; // Asigna 99 a valor_e
Ejemplo
char c = 'z';
char* pc = &c;
char** ppc = &pc;
char*** pppc = &ppc;
***pppc = 'm'; // cambia el valor de c a 'm'
pppc
ppc
pc
c z