Professional Documents
Culture Documents
Un puntero en C es una variable cuyo contenido es una direccin de memoria. Normalmente esta
direccin es una posicin de otra variable en la memoria. Los punteros son muy usados en C por las
siguientes razones:
&:- Es un operador unario (ampersan) (requiere de un solo operando) ste operador devuelve la
direccin de memoria de su operando.
*:- Es un operador de indireccin o dereferencia, devuelve el valor de la variable situada en la
direccin que contiene, ejemplos:
num = 5
conta = #
destino = *conta
Asignacin de Punteros
Despus de declarar un puntero, pero antes de asignarle un valor, el puntero contiene un valor
desconocido. Si se intenta utilizar el puntero antes de darle valor, se producir un fallo en el programa.
Un puntero que no apunte a ninguna posicin vlida de la memoria ha de tener asignado el valor nulo, que
es un cero. Se usa el valor nulo porque C++ garantiza que no existe ningn objeto en la direccin nula. As,
cualquier puntero que sea nulo indica que no apunta a nada y no debe ser usado.
Una forma de dar a un puntero el valor nulo es asignndole el valor cero. Por ejemplo, lo siguiente inicializa
el puntero p a nulo:
char *p = 0;
Adems, muchos de los archivos de cabecera de C++, como <cstdio>, definen NULL como el valor de
puntero nulo. Por eso tambin es posible ver la inicializacin de un puntero a nulo usando la constante
NULL (aunque realmente con esto le estamos asignando un 0). char *p = NULL;
NOTA: Un apuntador a cualquier tipo de variables es una direccin en memoria -- la cual es una direccin
entera, pero un apuntador NO es un entero.
La razn por la cual se asocia un apuntador a un tipo de dato, es por que se debe conocer en cuantos bytes
esta guardado el dato. De tal forma, que cuando se incrementa un apuntador, se incrementa el apuntador
por un ``bloque'' de memoria, en donde el bloque esta en funcin del tamao del dato.
Por lo tanto para un apuntador a un char, se agrega un byte a la direccin y para un apuntador a entero
largoo a flotante se agregan 4 bytes. De esta forma si a un apuntador a flotante se le suman 2, el apuntador
entonces se mueve dos posiciones float que equivalen a 8 bytes.
Punteros y Arreglos
En C existe una estrecha relacin entre punteros y arreglos suficientemente estrechas para que se
los trate simultneamente. Cualquier operacin que se pueda realizar mediante la indexacin de un arreglo
se puede realizar en base a punteros. En efecto el nombre del arreglo representa la direccin del elemento 0
del arreglo. La versin con punteros ser ms eficiente y por consiguiente ms rpida.
Lenguaje C permite dos mtodos de acceso a los elementos de un arreglo. Este hecho es importante
por que la aritmtica de punteros es ms rpida que los ndices de arreglos. Como la velocidad es un factor
importante en la programacin el uso de punteros para acceder a los elementos de un arreglo es comn en
C.
Indexando un puntero
En C se puede indexar un puntero como si fuera un arreglo. Esto indica nuevamente la estrecha
relacin entre punteros y arreglos, ejemplo:
int num[20], *pa;
pa=num;*/
Al aplicar el operador & a las dos partes de esta equivalencia &num[i]==num+i, se deduce que
&num[i] es lo mismo que num+i donde num+i es la direccin del i-simo elemento de num.
Por
otra
parte si pa es un apuntador en las expresiones puede presentarse con un sub ndice pa[i]==*(pa+i). Entonces
tenemos que en cualquier expresin en la que se tenga un arreglo y un sub ndice se puede escribir como un
puntero y un desplazamiento y viceversa.
Sin embargo existe una diferencia entre el nombre de un arreglo y un puntero.
Un apuntador es una variable por lo que operaciones como:
pa=num;
pa++;
/* son operaciones correctas. Pero el nombre de un arreglo es una direccin o puntero fijo de
ah que expresiones como las siguientes son totalmente ilegales */
++num;
num+=2;
En esencia, el nombre de un arreglo es un puntero al arreglo. Considerar lo siguiente:
int a[10], x;
int *ap;
ap = &a[0];
x = *ap;
*(ap + 1) = 100; /* Se asigna al segundo elemento de 'a' el valor 100 usando ap*/
Como se puede observar en el ejemplo la sentencia a[t] es idntica a ap+t. Se debe tener cuidado ya que C no
hace una revisin de los lmites del arreglo, por lo que se puede ir fcilmente ms all del arreglo en memoria
y sobrescribir otras cosas.
C sin embargo es mucho ms sutil en su relacin entre arreglos y apuntadores. Por ejemplo se puede teclear
solamente:
ap = a; en vez de ap = &a[0]; y tambin *(a + i) en vez de a[i], esto es, &a[i] es equivalente con a+i.
Y como se ve en el ejemplo, el direccionamiento de apuntadores se puede expresar como:
a[i] que es equivalente a *(ap + i)
Sin embargo los apuntadores y los arreglos son diferentes:
p++;
Se muestra enseguida una funcin para copiar una cadena en otra. Al igual que en el ejercicio anterior existe
en la biblioteca estndar una funcin que hace lo mismo.
void strcpy(char *s, char *t) {
x++;
a[n][m]
Cuando se pasa una arreglo bidimensional a una funcin se debe especificar el nmero de columnas -- el
nmero de renglones es irrelevante.
La razn de lo anterior, es nuevamente los apuntadores. C requiere conocer cuantas son las columnas para
que pueda brincar de rengln en rengln en la memoria.
Considerando que una funcin deba recibir int a[5][35], se puede declarar el argumento de la funcin como:
f( int a[][35] ) { ..... }
o an
En el ltimo ejemplo se requieren los parnteis (*a) ya que [ ] tiene una precedencia ms alta que *.
Por lo tanto:
int (*a)[35]; declara un apuntador a un arreglo de 35 enteros, y por ejemplo si hacemos la siguiente
referencia a+2, nos estaremos refiriendo a la direccin del primer elemento que se encuentran en el tercer
rengln de la matriz supuesta, mientras que int *a[35]; declara un arreglo de 35 apuntadores a enteros.
Ahora veamos la diferencia (sutil) entre apuntadores y arreglos. El manejo de cadenas es una aplicacin
comn de esto.
Considera:
char *nomb[10];
char anomb[10][20];
Punteros a Punteros
Como se ha visto un puntero es una variable que almacena direcciones y esta direccin es
usualmente la localizacin en memoria de otra variable. Sin embargo en C sta otra variable puede ser un
puntero.
Este no es el lmite de la relacin puntero si no que esto se puede extender de punteros a punteros,
etc. Pero esto nos llevara a un cdigo muy complicado de entender.
621
622
623
629
p
.. .
629
621
pp
num
puntero a puntero
num imprime 3
*p imprime 3
**pp imprime 3 *pp
629
int i,j,mat1[f][c],**mat2;
..
// inicializar al arreglo mat con cero
for(i=0;i<f;i++)
for(j=0;j<c;j++)
mat1[i][j]=0;
// inicializar al arreglo de punteros mat2 con cero usando aritmtica de punteros.
for(i=0;i<f;i++)
for(j=0;j<c;j++)
*(*(mat2+i)+j)=0;
nota : ver memoria dinmica
Punteros de tipo void
Esta posibilidad ya est presente en el ANSI C pero conviene citarla aqu tambin. Un puntero a void es un
puntero que no conoce en el momento de su definicin a qu tipo de dato va a apuntar. Un buen ejemplo de
esto es el valor de retorno de la funcin malloc(). Esta funcin reserva memoria dinmicamente para
cualquier tipo de dato, incluso para aquellos tipos de datos que haya definido el usuario.