You are on page 1of 6

Tutorial de punteros @ Club Desarrolladores

Tutorial de punteros
Publicado por Gastón el 31/08/2007 en C++ - Nivel Intermedio

Resúmen

En este artículo se intenta explicar en forma detallada que son, para que sirven y las práticas más comunes del
uso de punteros en el lenguaje C++.

Tabla de contenidos

¿Qué es un puntero?
Asignaciones de punteros
Aritmética de punteros
Comparación de punteros
Punteros, referencias y punteros a arrays. Utilización en las funciones.
Referencias
Los Arrays son punteros

¿Qué es un puntero?

Por definición un puntero es una variable que puede almacenar la dirección en memoria de otra variable. Según mi
definición, un puntero es una entidad, que puede ser variable o constante, que siempre contiene una dirección de
memoria (valida, inválida o nula), en la cual puede estar alojada una entidad de nuestro programa o no.
La declaración de una variable tipo puntero debe ser de la forma:

TipoVariableApuntada *NombreVariablePuntero;

Una variable de tipo puntero debe ser de igual tipo que la variable cuya dirección en memoria contiene, o dicho de
otra forma, la variable a la que apunta.

Un puntero no tiene asociación directa con el dato actual, pero si una asociación indirecta. Por ese motivo se usa el
termino ?indirección? cuando se hace referencia a una asociación indirecta.

Asignaciones de punteros

Cuando el compilador encuentra la declaración de una variable, le asigna una dirección en memoria en la que se
almacenarán los valores que sucesivamente se le asignen a esa variable. El operador & antepuesto al nombre de
una variable retorna el valor de la dirección inicial de memoria donde el compilador almacenó o almacenará el valor
de la variable. Para acceder al valor que se encuentra en la dirección apuntada por un puntero se debe
"dereferenciar" el puntero colocando * delante del mismo.
Por estos motivos se suele denominar a & el operador de referencia y a * el operador de indirección.
Veamos un ejemplo.

Página 1/6
Tutorial de punteros @ Club Desarrolladores

int *puntero; // Declara un puntero a una variable tipo int


int variable; /* Declara una variable tipo int.
El compilador identifica y asigna direccion (supongamos 0x2710, en Hexadecimal)
al identificador <variable> */
variable = 123456; /* Almacena en las direcciones 0x2710, 0x2711, 0x2712 y
0x2713
el valor <123456>, tomando en cuenta que una variable de tipo int ocupa 4 bytes.
Verifiquenlo en su compilador con sizeof(int) */
puntero = &variable; // Almacena 0x2710 en <puntero>

El operador * antepuesto a una variable puntero devuelve el valor que ésta almacena, partiendo de su dirección
inicial, en un número de celdas de memoria, que viene definido por el tipo de la variable apuntada. Entonces,
siguiendo con el ejemplo anterior:

int otra_variable; // Declara una variable tipo int


otra_variable = *puntero; /* Almacena en <otra_variable> el valor <123456>,
el valor que contiene <variable> que es apuntada por <puntero> */

Aritmética de punteros

Acabamos de ver asignaciones de punteros. Ahora veamos la aritmética de punteros.


Una variable del tipo char ocupa 1 byte en la memoria y una variable de tipo int ocupa 4 bytes (verifiquen que
tamaño tienen estos tipos de datos en sus compiladores).
Ahora bien, supongamos que creamos una variable de tipo char y ésta se aloja en la dirección 0x400, luego
creamos un puntero a esa variable.

char c; // se crea en 0x400


char* pc;
pc = &c; // pc ahora apunta a 0x400

Utilizando los operadores de adición y sustracción podemos movernos a partir de la dirección relativa a la que apunta
un puntero.

pc = pc + 1; /* pc ahora apunta a una direccion distinta,


ya que se ha desplazado 1 byte en sentido positivo (1 direccion de memoria más
alta),
es decir que pc paso de apuntar de 0x400 a 0x401 */

Para volver a la posición anterior solo debemos escribir: pc-- o pc = pc - 1 o pc -= 1, es indistinto. Lo mismo ocurre
con el operador +.

Si utilizamos otro tipo de dato, como por ejemplo int que ocupa 4 bytes, nos moveremos 4 unidades hacia delante
(+) o hacia detrás (-) dependiendo del operador que utilicemos.

Comparación de punteros

Para la comparación de punteros se utilizan los operadores básicos de comparación que usábamos con variables
bases, tales como int. Por lo que para saber por ejemplo si un puntero apunta a la misma dirección a la que apunta
otro, utilizaríamos: p1 == p2, para saber si son distintos utilizaríamos el operador !=, para saber si p1 apunta a una
dirección de memoria mas baja que p2 colocaríamos p1 < p2, y así con los demás operadores de comparación.

Página 2/6
Tutorial de punteros @ Club Desarrolladores

Punteros, referencias y punteros a arrays. Utilización en las funciones.

Estos tres conceptos están sumamente ligados entre si, y por ende con dirección de memoria. Ya vimos que un
puntero es una variable que contiene la dirección en memoria de otra variable, ahora veremos que uso se le puede
dar en las funciones.

Los punteros se utilizan en funciones por varios motivos:


Manipular completamente las variables que se pasan como argumento a la función, permitiendo que los cambios en
dichas variables se vean reflejados fuera de ella.

* Recuperar de una función más de un valor.


* Optimizar el procesamiento.
* Retornar referencias

Este ejemplo cumple con los tres primeros motivos mencionados (Referencias se ve en breve).

void intercambiar(int *a, int *b)


{
int aux;
aux = *a;
*a = *b;
*b = aux;
}

La función intercambia dos valores. Para ello solicita dos punteros a enteros, utilizando para acceder a estos
valores, el operador de indirección (*).
La llamada a la misma se realiza utilizando el operador de referencia (&).

int a = 1, b = 3;
intercambiar(&a, &b);
//como resultado la funcion intercambia los valores, a = 3 y b = 1

Si lo que queremos es retornar un puntero deberemos definir la función de otra forma, así que démosle además
una nueva funcionalidad, retornando el puntero al mayor de los dos números de ésta manera.

int* intercambiar(int *a, int *b)


{
int aux;
aux = *a;
*a = *b;
*b = aux;
return (*a > *b)? a: b;
}

int a = 1, b = 3, *c;
c = intercambiar(&a,&b);
ShowMessage("El mayor es: " + IntToStr(*c)); // que esta en a y en c

Referencias

Las referencias son seudónimos o alias que se aplican a otra entidad del mismo tipo. Para declarar una referencia
se coloca & después del tipo de variable y antes del identificador de la misma. Las variables de referencias
necesitan inicialización y éste valor (variable o literal) no podrá ser modificado.

Página 3/6
Tutorial de punteros @ Club Desarrolladores

int a; // supongamos direccion 0x2740


a = 5; // se asigna el valor 5 a la variable
int& b = a; // creamos la referencia b a la variable a

Tanto a como b están en la misma dirección de memoria, de tal manera que al modificar una de ellas, se modifica
la otra. Siguiendo el ejemplo la dirección de b es 0x2740 (la misma que a).

b = 7; // tanto a como b ahora almacenan 7


a = 0; // tanto a como b ahora almacenan 0

Por lo tanto, las referencias, se pueden pensar como punteros a una dirección de memoria fija.

Siguiendo con el ejemplo anterior, pero con referencias:

void intercambiar(int &a, int &b)


{
int aux;
aux = a;
a = b;
b = aux;
}

int a = 1, b = 3;
intercambiar(a, b);
//como resultado la funcion intercambia los valores, a = 3 y b = 1

Tanto el código con punteros como éste ultimo con referencias arrojan el mismo resultado, con la ventaja que el
último permite no utilizar el operador de indirección, además en C++ las referencias son muy utilizadas para pasar
argumentos a funciones (y como valores de retorno), no sólo para poderlos modificar dentro de la función, sino
también por motivos de eficiencia, pues es mucho más rápido pasar un puntero o una referencia de una variable
que una copia del valor de esa variable. Si además la variable es una estructura, las ventajas de eficiencia son
todavía mucho más notables.
No se debe confundir el uso de (&) en la declaración de una referencia con el operador dirección (&), de la misma
forma que no se debe confundir el carácter (*) en la declaración de un puntero, con el operador indirección (*).

El que una función tenga como valor de retorno una variable tipo referencia permite utilizarla de una manera un
poco singular. Considérese el siguiente ejemplo:

int& intercambiar(int &a, int &b)


{
int aux;
aux = a;
a = b;
b = aux;
return (a > b)? a: b;
}

Esto permite utilizarla, por ejemplo, del siguiente modo:

int a = 1, b = 3;
intercambiar(a,b) = 0;

Ésta es una forma un poco extraña de utilizar una función: la llamada está a la izquierda del operador de asignación,
en vez de aparecer a la derecha en una expresión aritmética o de otro tipo.
El resultado de esta llamada también es un poco extraño: el valor de retorno es una referencia, esto es un alias

Página 4/6
Tutorial de punteros @ Club Desarrolladores

del argumento de valor máximo. Cuando la llamada a la función se sustituye por su valor de retorno, el resultado
de la sentencia anterior es que la variable pasada como argumento que tiene mayor valor se hace igual a cero.
Este mismo efecto puede conseguirse mediante punteros, pero con referencias resulta mucho más sencillo.

Los Arrays son punteros

Los arrays no pueden ser declarados como variables referencia, porque ya tienen una forma propia y natural de
ser pasados como argumentos a una función. Pero primero definamos como asignar un array de una dimensión a un
puntero.

int array[5];
int *p;
p = array; // p = &array[0]; la direccion del primer elemento [0]

Para un array de 2 dimensiones

int array[5][4];
int *p;
p = &array[0][0]; // la direccion del primer elemento [0][0]

Para un array de 3 o mas dimensiones (tres en este ejemplo).

int array[5][4][3];
int *p;
p = &array[0][0][0]; // la direccion del primer elemento [0][0][0]

Por lo que un array se puede pensar como un puntero a la dirección inicial de memoria donde comienza.
Creamos un procedimiento que inicialice el array de una dimensión, para esto podemos definirlo de varias maneras,
la primera pide un array de enteros de 5 elementos, la segunda un array de enteros con cantidad de elementos
desconocidos, la tercera un puntero a un entero y la última un array de 4567 elementos, en realidad todas están
pidiendo un puntero a la dirección del primer elemento del array.

void inicializar(int a[5])


//o void inicializar(int a[])
//o void inicializar(int *a)
//o incluso void inicializar(int a[4567])
{
for(int i = 0; i < 5; i++)
a[i] = 0;
}

Para hacer uso de ésta función utilizamos éste formato de llamada. Las dos formas son equivalentes.

int array[5], *p;


p = array;
inicializar(array);// o inicializar(p);

Para el caso del array de dos dimensiones:

Página 5/6
Tutorial de punteros @ Club Desarrolladores

void inicializar(int a[5][4])


//o void inicializar(int a[][4])
//o incluso void inicializar(int a[4567][4])
{
for(int i = 0; i < 5; i++)
for( int j = 0; j < 4; j++)
a[i][j] = 0;
}

int array[5][4];
inicializar(array);

Para el caso del array de tres dimensiones:

void inicializar(int a[5][4][3])


//o void inicializar(int a[][4][3])
//o incluso void inicializar(int a[4567][4][3])
{
for(int i = 0; i < 5; i++)
for( int j = 0; j < 4; j++)
for( int k = 0; k < 3; k++)
a[i][j][k] = 0;
}

int array[5][4][3];
inicializar(array);

Sobre el autor

Gastón tiene 28 años, vive en Argentina / Santa Fe / Santa Fe y su ocupación es Desarrollador de


aplicaciones web.

Ha publicado 31 artículos en clubdesarrolladores con un promedio de valoración de 7.80 puntos. Puedes


visitar su sitio web en http://www.clubdesarrolladores.com

Descargado de Club Desarrolladores - Visitanos en http://www.clubdesarrolladores.com

Página 6/6

You might also like