[Índice][Previo]
[Siguiente]
Punteros
El concepto de puntero está unido a la forma en que los tipos de datos son almacenados en la
memoria de un ordenador, ya que denotan la dirección (address) o localización de una
variable determinada. El nombre de la variable determina el tipo (char, int, float o double) y su
dirección determina dónde está almacenada. Conocer la dirección de una
variable es importante porque:
- Permite que las funciones cambien el valor de sus argumentos, como veremos en el
capítulo siguiente.
- Permite pasar vectores de forma eficiente entre funciones: en lugar de copiar cada elemento
del vector, se copia la dirección del primer elemento.
- Permite reservar memoria en tiempo de ejecución en lugar de en tiempo de
compilación, lo que significa que el tamaño de un vector puede ser determinado por el
usuario en lugar de por el programador.
El nombre de un array es un puntero al array. Por tanto, los punteros y los arrays están
íntimamente ligados en C y en C++.
Terminología básica.
Para entender los punteros y los vectores, es necesario conocer primero cómo se almacenan
los números en la memoria del ordenador. El valor de cada variable en un programa de
ordenador se guarda en una sección de memoria cuyo tamaño está determinado por
el tipo de dato de la variable. La localización de esta sección de memoria es
almacenada en la dirección de la variable. Por tanto, es como si cada variable estuviera
compuesta de dos partes: su valor y su dirección. Cada celda de memoria se puede considerar
compuesta de una parte con el contenido, y otra en la que se almacena la dirección. Esto es
análogo a una fila de casas: cada casa tiene diferentes contenidos, y para mirarla
necesitamos conocer su dirección.
Las direcciones se representan normalmente por un número hexadecimal, pudiendo contener un
carácter, un entero o un real (aunque en realidad todos son almacenados como números
binarios).
Para obtener la dirección de una variable se utiliza el operador dirección &:
#include <iostream.h>
main()
{
double d = 2.7183;
cout << "numero = " << d << "\tdirección = " << &d
<< '\n';
}
El valor de d es 2.7183. El valor de &d es una dirección (donde 2.7183 está
almacenado). La dirección es imprimida en formato hexadecimal.
Direcciones y punteros
Un puntero guarda la dirección de un objeto en memoria, y como tal un puntero es
también una variable. Puede parecer algo confuso, es como decir que el contenido de una casa
es la dirección de otra vivienda. Las direcciones se guardan como números
hexadecimales, por lo que no hay ninguna razón por la que no podamos definir otro tipo de
dato, similar a un entero, pero a través del cual se puede modificar el valor almacenado en
esa dirección. Es importante entender la relación entre punteros y direcciones:
- Cada variable tiene su dirección, que puede ser obtenida mediante el operador unario
&.
- La dirección de una variable puede ser almacenada en un tipo de dato llamado puntero.
Un puntero en C o en C++ se declara anteponiendo un * al nombre de la variable, que es el operador
inverso a &. El puntero apunta
entonces a una variable del tipo especificado, y no debe ser usado con variables de otros tipos. Un
experto en C podría forzar la utilización de un puntero con un tipo distinto del que
se ha declarado, pero no es recomendable, ya que podría conducir a un uso erróneo.
Veamos algunos ejemplos de declaración de punteros:
int *puntero1;
int *puntero2, *puntero3;
char variable, *punteroCaracter;
float *punteroReal, real;
En la primera línea, declaramos un puntero a un entero. En la
segunda, dos punteros a entero. En la tercera, un carácter (
variable
) y un puntero a carácter (punteroCaracter
).
Por último, punteroReal
es un puntero a un real,
y real
es declarado como un número real.
Veamos un ejemplo de uso del operador * y del operador de dirección (&):
#include <iostream.h>
main(){
double d, *dp;
d = 2.7183;
dp = &d;
cout << "numero = " << d << "\tdirección = " << &d
<< '\n';
}
Veamos un programa completo:
# include <iostream.h>
main ()
{
int *ptInt;
int var1 = 7, var2 = 27;
ptInt = &var1;
var2 = *ptInt;
cout << " var1 = " << var1 << " var2 = "
<<var2 << "*ptInt = " <<*ptInt << '\n';
*ptInt = 5;
cout << " var1 = " << var1 << " var2 = "
<<var2 << "*ptInt = " <<*ptInt << '\n';
ptInt = &*ptInt;
var1 = *&var1;
}
El resultado de la ejecución es:
var1 =7 var2 = 7 *ptInt = 7
var1 = 5 var2 =7 *ptInt = 5
Estudiemos el funcionamiento del programa:
- Se asigna a ptInt la dirección de var1. Entonces el valor de ptInt es la
dirección de memoria de var1.
- A var2 se asigna el valor al que ptInt apunta. Entonces el valor de var2 es el contenido de
la localización de memoria la que ptInt apunta (var1).
- Después de imprimir los tres valores por primera vez, el contenido de la
dirección a la que apunta ptInt es cambiado a 5. Como este contenido es var1, el valor de
var1 es ahora 5, pero var2 no es modificado.
- Las dos últimas líneas ilustran cómo los operadores * y & son conceptos
inversos. Nótese que el orden de precedencia es de izquierda a derecha, por tanto el
más cercano a la variable es siempre el primero que se aplica.
Otro ejemplo:
#include <iostream.h>
main()
{
int i = 2;
int *ip = &i;
int **ipp = &ip;
int ***ippp = &ipp;
cout << " i = " << i << endl
    << " *ip = " << *ip << endl
    << " *ipp = " << *ipp << endl
    << " *ippp = " << *ippp << endl
    << " &i = " << &i << endl
    << " ip = " << ip << endl
    << " ipp = " << ipp << endl
    << " ippp = " << ippp << endl;
}
La salida de este programa es:
i = 2
*ip = 2
*ipp = 0x11ffff908
*ippp = 0x11ffff900
&i = 0x11ffff908
ip = 0x11ffff908
ipp = 0x11ffff900
ippp = 0x11ffff8f8
[Índice][Previo]
[Siguiente]
Última modificación: 1-4-97
Comentarios, sugerencias, ideas...
© Beatriz Fuentes Arenaz, 1996-1997