Академический Документы
Профессиональный Документы
Культура Документы
Es una Variable que representa la posicin (en vez del valor) de otro dato, tal
como una variable o un elemento de una formacin. Los punteros son usados
frecuentemente en C y tienen gran cantidad de aplicaciones, por ejemplo,
pueden ser usados para trasvasar informacin entre una funcin y sus puntos
de llamada. En particular proporcionan una forma de devolver varios datos
desde una funcin a travs de los argumentos de la funcin.
Punteros a funciones
float *ptr1; /* ptr apunta a un valor float */
float *mifun(void); /* la funcin mifunc devuelve un
puntero a un valor float */
La declaracin
int (*ptrafuncion((void);
crea un puntero a una funcin que devuelve un entero y la declaracin
float (*ptrafuncion1)(int x, int y);
declara ptrafuncion1 como un puntero a una funcin que devuelve un valor
float y requiere dos
argumentos enteros.
PUNTEROS Y FUNCIONES
La relacin entre los punteros y las funciones , puede verse en tres casos
distintos , podemos pasarle a una funcin un puntero como argumento
(por supuesto si su parmetro es un puntero del mismo tipo ) , pueden
devolver un puntero de cualquier tipo , como ya hemos visto con
malloc() y calloc() , y es posible tambin apuntar a la direccin de la
funcin , en otras palabras , al cdigo en vez de a un dato.
PUNTEROS COMO PARAMETROS DE FUNCIONES .
Supongamos que hemos declarado una estructura , se puede pasar a
una funcin como argumento , de la manera que ya vimos
anteriormente:
struct conjunto {
int a
double b ;
char c[5] ;
} datos
double b ;
char c[5] ;
} *pdatos
Punteros y funciones
Introduccin
Absolutamente todos los datos en C pueden ser tratados como
punteros y por ello este lenguaje proporciona una serie de importantes
herramientas para trabajar con ellos.
Punteros
Qu son los punteros ?
Como su nombre indica un puntero es algo que apunta, es decir,
nos indica dnde se encuentra una cierta cosa. Supongamos (como
otras tantas veces) que disponemos de un gran archivo en el que
almacenamos informes. Este fichero est dividido en
compartimientos, cada uno de los cuales contiene uno de nuestros
informes (esto sera equivalente a las variables con las que hemos
trabajado hasta ahora -informes-, la cuales contienen informacin, y el
archivo representa la memoria de nuestro ordenador, obviamente las
variables se almacenan en la memoria). Sin embargo otros
compartimientos no contienen informes, sino que lo que contienen es
una nota que nos dice dnde est ese informe.
Supongamos que como mximo trabajamos con tres informes a la
vez, digamos que no nos gusta leer demasiado, y reservamos, por
tanto, tres compartimientos en los indicamos en que compartimiento
se encuentran esos tres informes. Estos tres compartimientos seran
nuestros punteros y como ocupan un compartimiento en el archivo
(nuestra memoria) son realmente variables, pero variables muy
especiales. Estas variables punteros ocupan siempre un tamao fijo,
simplemente contienen el nmero de compartimiento en el que se
encuentra la informacin. No contienen la informacin en s.
Punteros y matrices
Ya hemos hablado de las matrices en el tema anterior. Se trataba
de un conjunto de un nmero de terminado de variables de un mismo
tipo que se referenciaban con un nombre comn seguido de su
posicin entre corchetes con relacin al primer elemento. Todas las
entradas de una matriz estn consecutivas en memoria, por eso es muy
sencillo acceder al elemento que queramos en cada momento
simplemente indicando su posicin. Slo se le suma a la posicin
inicial ese ndice que indicamos. Es un ejemplo que casa
perfectamente con nuestro ejemplo de los informes, cada informe
podra ser considerado como una matriz de tantos elementos como
pginas tenga el informe y en los que cada uno de ellos es un tipo de
datos llamado pgina.
Las matrices son realmente punteros al inicio de una zona
consecutiva de los elementos indicados en su declaracin, por lo cual
podemos acceder a la matriz utilizando los corchetes como ya vimos o
utilizando el operador *.
elemento[i] <=> *(elemento +i)
Como ya se ha comentado todos los punteros ocupan lo mismo en
memoria, el espacio suficiente para contener una direccin, sin
embargo cuando se declaran es necesario indicar cul es el tipo de
datos al que van a apuntar (entero, real, alguna estructura definida por
el usuario). En nuestro ejemplo tendramos un tipo de puntero
por cada tipo de informe distinto, un puntero para informes de una
pgina, otro puntero para informes de 2 pginas y as sucesivamente.
En principio esto es irrelevante por que una direccin de memoria es una
direccin de memoria, independientemente de lo que contenga con lo
cual no sera necesario declarar ningn tipo, pero esta informacin
es necesaria para implementar la aritmtica de punteros que
ejemplificaremos a continuacin.
*punt_pgina;
i1[10],*punt1;
i3[5],*punt2;
i4[15],*punt3;
....
Por tanto disponemos de un puntero a pginas y tres
punteros, uno para cada tipo de informe y tres matrices de distintos
tipos de informes que nos permiten almacenar en nuestro archivo un
mximo de 30 informes (10 de 1 pgina, 5 de 5 pginas y 15 de 25
pginas).
Supongamos que en el programa principal se llenan esas
matrices con datos (por teclado o leyendo de un fichero, por
ejemplo) y realizamos las siguientes operaciones:
punt_pgina = (pgina *) &i4[0];
punt3
= (informe3 *)&i4[0];
Los cast (que comentamos en el tema 1) convierten las
direcciones al tipo apropiado, las direcciones que contendrn
punt_pgina y punt3 sern exactamente iguales, apuntarn al
principio del primer informe de tipo3. Sin embargo punt_pgina es un
puntero de tipo pgina y punt3 es un puntero de tipo informe3, qu
significa sto?. Si ejecutsemos una instruccin como sta:
punt_pgina = punt_pgina + 5;
punt_pgina pasara a apuntar a la quinta pgina del primer
informe de tipo 3 (i4[0]), puesto que punt_pgina es un puntero de
pginas. Mientras que si la operacin fuese:
punt3 = punt3 + 5;
punt3 pasara a apuntar a el quinto informe de tipo 3 (i4[5]),
puesto que punt3 es un puntero a informes de tipo tres. Si ahora
realizsemos la operacin:
punt_pgina = (pgina *)punt3;
Ahora punt pgina apuntara a la primera pgina del quinto
informe de tipo 3. En esto consiste la aritmtica de punteros, cuando
se realiza una operacin aritmtica sobre un puntero las unidades de
sta son el tipo que se le ha asociado a dicho puntero.
Si el puntero es de tipo pgina operamos con pginas, si es de tipo
informes operamos con informes. Es evidente que un informe de tipo 3 y
una pgina tienen distintos tamaos (un informe de tipo 3 son 25
pginas por definicin).
Como hemos visto las matrices se pueden considerar como
punteros y las operaciones con esos punteros depende del tipo
asociado al puntero, adems es muy recomendable utilizar el cast
cuando se realizan conversiones de un tipo de puntero a otro.
Punteros y cadenas de caracteres
Como su propio nombre indica una cadena de caracteres es
precisamente eso un conjunto consecutivo de caracteres. Como ya
habamos comentado los caracteres se codifican utilizando el cdigo
ASCII que asigna un nmero desde 0 hasta 255 a cada uno de los
smbolos representables en nuestro ordenador. Las cadenas de
caracteres utilizan el valor 0 ('\0') para indicar su final. A este tipo de
codificacin se le ha llamado alguna vez ASCIIZ (la Z es de zero).
Las cadenas de caracteres se representan entre comillas dobles
(") y los caracteres simples, como ya habamos indicado con comillas
simples ('). Puesto que son un conjunto consecutivo de caracteres la
forma de definirlas es como una matriz de caracteres.
char identificador[tamao_de_la_cadena];
*identificador;
matriz de caracteres */
gets(cadena); /* Cuando llenos sobre cadena ahora
estamos leyendo sobre cadena2, debido al efecto de la instruccin
anterior */
puts(cadena2); /* SI imprimimos ahora cadena2 la pantalla
nos mostrar la cadena que acabamos de leer por teclado */
}
En el programa vemos como utilizamos cadena que solamente es
un puntero para apuntar a distintas zonas de memoria y utilizar
cadena1 o cadena2 como destino de nuestras operaciones. Como
podemos ver cuando cambiamos el valor de cadena a cadena1 o
cadena2 no utilizamos el operador de direccin &, puesto que como
ya hemos dicho una matriz es en s un puntero (si slo indicamos su
nombre) y por tanto una matriz o cadena de caracteres sigue siendo un
puntero, con lo cual los dos miembros de la igualdad son del mismo tipo
y por tanto no hay ningn problema.
Funciones
Introduccin
Hasta el momento hemos utilizado ya numerosas funciones,
como printf o scanf, las cuales forman parte de la librera estndar de
entrada/salida (stdio.h). Sin embargo el lenguaje C nos permite definir
nuestras propias funciones, es decir, podemos aadir al
lenguaje tantos comandos como deseemos.
Las funciones son bsicas en el desarrollo de un programa cuyo
tamao sea considerable, puesto que en este tipo de programas es
comn que se repitan fragmentos de cdigo, los cuales se pueden
incluir en una funcin con el consiguiente ahorro de memoria. Por otra
parte el uso de funciones divide un programa de gran tamao en
subprogramas ms pequeos (las funciones), facilitando su
comprensin, as como la correccin de errores.
Cuando llamamos a una funcin desde nuestra funcin
principal main() o desde otra funcin lo que estamos haciendo
realmente es un salto o bifurcacin al cdigo que le hayamos
asignado, en cierto modo es una forma de modificar el flujo de
control del programa como lo hacamos con los comandos while y for.
Definicin de funciones
Ya hemos visto cual es la estructura general de una funcin puesto
que nuestro programa principal, main() no es otra cosa que una
funcin. Veamos cual es el esquema genrico:
tipo_a_devolver identificador (tipo1 parmetro1, tipo2 ...)
{
tipo1 Variable_Local1;
tipo2 Variable_Local2;
...
Cdigo de la funcin
return valor del tipo valor a devolver;
}
Lo primero con lo que nos encontramos es la cabecera de la
funcin. Esta cabecera est formada por una serie de
declaraciones. En primer lugar el tipo_a_devolver.
Todas las funciones tienen la posibilidad de devolver un valor,
aunque pueden no hacerlo. Si definimos una funcin que nos calcula el
coseno de un cierto ngulo nos interesara que nuestra funcin
devolviese ese valor. Si por el contrario nuestra funcin
realiza el proceso de borrar la pantalla no existira ningn valor que nos
interesase conocer sobre esa funcin. Si no se especifica ningn
parmetro el compilador supondr que nuestra funcin devuelve un
valor entero (int).
A continuacin nos encontramos con el identificador de la funcin,
es decir, el nombre con el que la vamos a referenciar en nuestro
programas, seguido de una lista de parmetros entre parntesis y
separados por comas sobre los que actuar el cdigo
que escribamos para esa funcin. En el caso de la funcin coseno a la
que antes aludamos, el parmetro sera el ngulo calculamos el coseno
de un cierto ngulo que en cada llamada a la funcin probablemente
sea distinto. Vase la importancia de los parmetros, si no
pudisemos definir un parmetro para nuestra funcin coseno,
tendramos que definir una funcin para cada ngulo, en la que
obviamente no indicaramos ningn parmetro.
A continuacin nos encontramos el cuerpo de la funcin. En primer
lugar declaramos las variables locales de esa funcin.
for (i=0;i<longitud;i++)
if (vector[i] == valor) break;
return i;
}
Esta funcin busca un valor en un vector de nmeros enteros y
devuelve el ndice dentro de la matriz de la entrada de sta que lo
contiene. Puesto que devuelve el ndice de la matriz supondremos en
principio un valor de retorno entero para ese ndice. Los parmetros
que debe conocer la funcin son: la matriz en la que buscar, el valor
que debemos buscar y la longitud de la matriz. Podramos haber
realizado una funcin a medida para que utilizase una matriz de un
nmero determinado de elementos (int
vector[100], por ejemplo) y ahorrar el parmetro longitud, sin
embargo con la definicin que hemos hecho nuestra funcin
funcionar con matrices de cualquier longitud de enteros.
Hemos declarado adems una variable local que es necesaria para
la realizacin del bucle actuando como contador y conteniendo adems
()
matriz1[20];
matriz2[30];
indice,dato;
-Funcin main()
-Espacio para la variable c (Posicin de memoria x)
-Espacio para la variable d (Posicin de memoria y)
-Inicializacin de las variables
-swap(c,d)
-Fin de main()
-Funcin swap
-Cdigo de la funcin swap
-Espacio privado para almacenar los parmetros (Posicin
de memoria z)
En este ltimo compartimiento es dnde almacenamos los
valores de nuestros parmetros que sern respectivamente 5 y 7.
Despus de la ejecucin de swap en esta zona de memoria los
valores estn intercambiados, nuestro parmetro a que se
corresponde con la variable c en la llamada a swap contendr el valor
7 y el parmetro b correspondiente a d en la funcin main contendr el
valor 5. Esto es lo que se encuentra almacenado en la zona privada de
memoria de la funcin. Con este esquema cuando la funcin swap
termina su ejecucin y se devuelve el control al programa principal
main, los valores de c y d no han cambiado, puesto que los
compartimientos o posiciones de memoria x e y no han sido tocados
por la funcin swap, la cual slo ha actuado sobre el compartimiento z.
Si declaramos ahora nuestra funcin swap como sigue:
swap (int *p1,int *p2)
{
int
t;
t = *p1; /*Metemos en t el contenido de p1 */
*p1 = *p2; /* Contenido de p1 = contenido de p2 */
*p2 = t;
}
Tendremos el mismo esquema de nuestra memoria que antes
pero en lugar de almacenar en la zona privada de la funcin swap para
los parmetros los valores 5 y 7 tenemos almacenados en ella
los compartimientos en los que se encuentran, sto es, hemos
almacenado las posiciones x e y en lugar de 5 y 7. De esta forma
accedemos mediante un puntero a las variables c y d del programa
principal que se encuentran en las posiciones x e y modificndolas
directamente as que al regresar al programa principal sus valores
se encuentran ahora intercambiados.