You are on page 1of 7

4. Conceptos bsicos de apuntadores.

Introduccin.
Los apuntadores o punteros son una parte fundamental de C. Si usted no puede
usar apuntadores apropiadamente, entonces usted ha perdido bsicamente todo el
poder y flexibilidad que C permite. El secreto para C est en el uso de apuntadores.
C emplea mucho los apuntadores. Por qu?:

Esta es la nica forma de expresar algunos clculos.

Estos producen cdigo eficiente y compacto.

Estos dan una herramienta muy poderosa.

C usa apuntadores implcitamente con:

Arreglos.

Estructuras.

Funciones.

Los apuntadores quizs sean la parte ms difcil del entendimiento de C.


4.1 Concepto de apuntador.
Todos los objetos (datos) a excepcin de las variables register residen en algn
lugar en la memoria; ese "algn lugar" tiene una direccin. Para los sistemas
(computadoras) que numeran cada byte de memoria en secuencia iniciando desde
cero, una direccin es solamente el nmero de secuencia de un byte.
Un apuntador es una variable la cual contiene la direccin de memoria de otra
variable o simplemente podemos decir que un apuntador es una direccin.
El siguiente programa muestra cmo encontrar la direccin de variables.
#include <stdio.h>
int main(void)
{
short int i=7, j=8;
printf("i == %hd, &i == %p\n", i, &i);
printf("j == %hd, &j == %p\n", j, &j);
return 0;
}
La salida en mi sistema es:

i == 7, &i == FFF4
j == 8, &j == FFF2
pero puede variar de sistema a sistema.
El operador unario & (ampersand) regresa "la direccin de un objeto dato
(variable)". El caracter de conversin %p despliega una direccin en un formato
dependiente del compilador (usualmente hexadecimal).
La distribucin de la memoria para i y j del ejemplo anterior se muestra a
continuacin:

El lugar donde su compilador asigna la memoria no es crtico. Por ejemplo, i y j


pueden estar adyacentes en memoria, pero algunas arquitecturas dejan intervalos
entre las variables, debido a requerimientos de alineacin. Note que mi compilador
asigna i despus de j en memoria ("despus" significa una direccin de memoria
ms alta).
Cmo la computadora guarda los bits de un nmero tambin depende de su
sistema. De hecho en la PC, el 7 en i realmente no es guardado en la porcin de
memoria ms a la derecha de i. Usted puede pensar sto la mayora de las veces
debido a expresiones como 0x0007. No importa como los bits son fsicamente
puestos es memoria.
Un apuntador es una variable que retiene la direccin de otro objeto. Usualmente
se usa para referirse a un objeto en memoria sin interesar el valor numrico de la
direccin.
4.2 Declaracin de apuntador.
Para declarar un apuntador a una variable, hacemos, por ejemplo:
int *ip;

/* Declara a ip como un apuntador a entero */

Un apuntador "siempre" apunta a un objeto de algn tipo, as que el tipo


referenciado siempre debe aparecer en la declaracin (nosotros hablamos de
apuntador a int, apuntador a char, etc.). El siguiente programa ilustra sto.
#include <stdio.h>
int main(void)
{
int i = 7;
int j = 8;
int *ip; /* Declara apuntador a entero */
int *jp; /* Otro apuntador a entero */
ip = &i; /* Obtiene la direccin de i */
jp = &j; /* Obtiene la direccin de j */
printf("La direccin %p (ip) contiene %d (i)\n", ip, i);
printf("La direccin %p (jp) contiene %d (j)\n", jp, j);

return 0;

Normalmente la ubicacin en memoria de las variables no es importante, por lo


que es usual ignorar la localidad de memoria y referirnos a ellas de la siguiente
forma:

Usualmente se dice que ip apunta a i o que jp apunta a j.


La nocin de un apuntador es tan simple que los novatos a menudo se frustran
buscando otras cosas. Si quiere eliminar horas de confusin, slo recuerde sto:
Un apuntador es una direccin
Note que lo anterior dice que un apuntador es una direccin en lugar de retiene
una direccin. Ambos son verdaderos. Un apuntador es una direccin al igual que
un int es un entero; usualmente usted no dice que un int i, por ejemplo, "retiene"
un entero. Slo se quiere enfatizar que cuando use apuntadores, piense en
direcciones.
4.3 Indireccin.
Cuando un asterisco precede a un apuntador, la expresin resultante se refiere al
valor apuntado. La declaracin int *ip; indica que *ip es un int, por tanto ip es un
apuntador a int.
El proceso de referirse a memoria indirectamente por medio de un apuntador es
llamado indireccin o derreferencia.
El siguiente programa ilustra el uso de apuntadores:
#include <stdio.h>
int main(void)
{
int i = 7, j = 8;
int *ip, *jp;
ip = &i;
jp = &j;
printf("La direccin %p (ip) contiene %d (i)\n", ip, *ip);
printf("La direccin %p (jp) contiene %d (j)\n", jp, *jp);
*ip = 10; /* Indireccin */
printf("Ahora la direccin %p (ip) contiene %d (i)\n", ip, i);
*jp = 15; /* Indireccin */
printf("Ahora la direccin %p (jp) contiene %d (j)\n", jp, j);
return 0;
}

La indireccin puede ocurrir en cualquier lado de un estatuto de asignacin. Para


el ejemplo anterior:
*ip = 10;
tiene el mismo efecto que:
i = 10;
Si usted
pudiera definir un
apuntador sin
mencionar el tipo al que
hace
referencia, la expresin *ip
no tiene
significado y la indireccin
es imposible
[11]. Nunca olvide que un
apuntador no slo apunta a algn lugar en memoria; sino que adems, apunta a un
objeto de algn tipo. La nica excepcin a esta regla pasa cuando usted asigna un
apuntador al valor NULL. Usted puede comparar un apuntador con el valor de NULL.
La distribucin de la memoria para el ejemplo anterior es, en algn sistema dado:

Aunque las direcciones usualmente aparecen como nmeros, no se debe asumir


que existe alguna relacin entre apuntadores y tipos de datos integrales (int,
long). Los apuntadores son tipos de datos nicos y debern ser tratados como
tales.
Las nicas cosas que usted puede hacer con los apuntadores son:

Guardar y leer la direccin de un objeto del tipo referenciado.

Alterar o recuperar los contenidos en esa direccin (indireccin).

Sumar o restar un entero.

Restarlo de otro apuntador del mismo tipo.

Compararlo con otro apuntador.

Asignarlo o compararlo a NULL.

Pasarlo como argumento a una funcin.

Ejemplo:
int i=7, j=8, n;
int *ip, *jp;
1) ip=&i;

2) *ip=9;
3) ip=ip+2;
4) n=ip-jp;
5) if (ip==jp)
...
6) ip=NULL;
7) scanf("%d",ip);
Normalmente la ubicacin en memoria de las variables no es importante, por lo
que es usual ignorar la localidad de memoria y referirnos a ellas de la siguiente
forma:

Una vez que la direccin de una variable se asigna a un apuntador se dice


que el apuntador apunta a la variable; para el ejemplo anterior, se dice que ip
apunta a i o que jp apunta a j.
La nocin de un apuntador es tan simple que los novatos a menudo se
frustran buscando otras cosas. Si quiere eliminar horas de confusin, slo
recuerde sto:
Un apuntador es una direccin
Note que lo anterior dice que un apuntador es una direccin en lugar de
retiene una direccin. Ambos son verdaderos. Un apuntador es una direccin al
igual que un int es un entero; usualmente usted no dice que un int i, por
ejemplo, "retiene" un entero. Slo se quiere enfatizar que cuando use
apuntadores, piense en direcciones.

4.4 Apuntador a apuntador.


Debido a que todos los objetos tienen una direccin, usted puede tener
apuntadores a cualquier tipo de objetos, incluyendo otro apuntador.
El siguiente programa muestra como definir un apuntador a un apuntador a
entero.
#include <stdio.h>
int main(void)
{
int i = 7;
int *ip = &i;

/* ip es un apuntador a entero */

int **ipp = &ip; /* ipp es un apuntador a apuntador a entero */


printf("La direccin %p (ip) contiene %d (i)\n", ip, *ip);
printf("La direccin %p (ipp) contiene %p (ip)\n", ipp, *ipp);
printf("**ipp (i) == %d (i)\n", **ipp);
return 0;
}
La salida del programa es:
La direccin 0027FF44 (ip) contiene 7 (i)
La direccin 0027FF40 (ipp) contiene 0027FF44 (ip)
**ipp (i) == 7 (i)
El diagrama para el programa anterior es:

Si ipp es un apuntador a un apuntador a un entero, entonces *ipp es un


apuntador a entero (ip). Para llegar finalmente al entero 7 en i se requiere de otro
nivel de indireccin, de ah la expresin **ipp. En otras palabras: **ipp == *ip ==
i.
4.5 Introduccin a la aritmtica de apuntadores.
En construccin ...
Sea p un apuntador no nulo, entonces, sumarle o restarle un entero n es igual a
mover el apuntador n veces el tamao del tipo referido por p.
p n = (char *)p n*sizeof(*p)

Errores comunes.
Errores comunes con apuntadores.
En esta seccin se quiere hacer hincapi en los errores ms comunes cometidos por los
novatos en la programacin C.
Error 1. No asignar o inicializar un apuntador antes de usarlo.
No asignar un apuntador a una direccin de memoria antes de usarlo es un error
bastante frecuente:
int *p;
*p = 6;
Este tipo de error es muy peligroso y podra NO ser detectado por el compilador, el
comportamiento del programa no est definido.

Principio bsico: Inicializar antes de usar apuntadores.


Error 2. Indireccin ilegal.
Ahore inicialice un apuntador a NULL y considere lo siguiente:
int i = 5;
int *p = NULL; /* NULL es el "cero" para apuntadores */
*p = &i;
*p = 6;
El cdigo anterior NO modifica el valor de la variable i, el error se encuentra en:
*p = &i;
y ser detectado en tiempo de ejecucin por haber inicializado p a NULL.
La solucin es:
int i = 5;
int *p = NULL;
p = &i;
*p = 6;

Notas:

La constante simblica NULL se encuentra definida en el estndar C.

NULL se interpreta como el valor cero de los apuntadores.

Un apuntador puede ser inicializado a NULL

Un apuntador puede ser comparado a NULL

No est definida la indireccin *ptr cuando ptr es NULL, se genera error


en tiempo de ejecucin.

Es error de compilacin querer hacer indireccin *ptr cuando ptr es un


apuntador void.