16
 Puntero (Lenguaje C) Es una Variable que representa la posición (en vez del valor) de otro dato, tal como una variable o un elemento de una formación Los punteros son usados frecuentemente en C ! tienen gran cantidad de aplicaciones, por ejemplo, pueden ser usados para trasvasar información entre una función ! sus puntos de llamada En particular proporcionan una forma de devolver varios datos desde una función a trav"s de los argumentos de la función Punteros a funciones #oat $ptr%& '$ ptr apunta a un valor #oat $' #oat $mifun(void)& '$ la función mifunc devuelve un puntero a un valor #oat $' La declaración int ($ptrafuncion((void)& crea un puntero a una función que devuelve un entero ! la declaración #oat ($ptrafuncion%)(int , int !)& declara ptrafuncion% como un puntero a una función que devuelve un valor #oat ! requiere dos argumentos enteros P*+E-. / 0*C1-*E. La relación entre los punteros ! las funciones , puede verse en tres casos distintos , podemos pasarle a una función un puntero como argumento (por supuesto si su par2metro es un puntero del mismo tipo ) , pueden devolver un puntero de cualquier tipo , como !a 3emos visto con malloc() ! calloc() , ! es posible tambi"n apuntar a la dirección de la función , en otras palabras , al código en vez de a un dato P*+E-. C-4- P554E+-. 6E 0*C1-*E. .upongamos que 3emos declarado una estructura , se puede pasar a una función como argumento , de la manera que !a vimos anteriormente7 struct conjunto 8  int a &  double b &  c3ar c9:; &  < datos &  void una=funcion( struct conjunto datos )&

Lenguaje C

Embed Size (px)

DESCRIPTION

Lenguaje C ejemplos

Citation preview

Puntero (Lenguaje C)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 funcionesfloat *ptr1; /* ptr apunta a un valor float */float *mifun(void); /* la funcin mifunc devuelve unpuntero a un valor float */La declaracinint (*ptrafuncion((void);crea un puntero a una funcin que devuelve un entero y la declaracinfloat (*ptrafuncion1)(int x, int y);declara ptrafuncion1 como un puntero a una funcin que devuelve un valor float y requiere dosargumentos enteros.

PUNTEROS Y FUNCIONESLa 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 ; void una_funcion( struct conjunto datos );Hicimos notar, en su momento, que en este caso la estructura se copiaba en el stack y as era pasada a la funcin, con el peligro que esto implicaba, si ella era muy masiva, de agotarlo.Otra forma equivalente es utilizar un puntero a la estructura :struct conjunto { int a ; double b ; char c[5] ; } *pdatos ; void una_funcion( struct conjunto *pdatos ) ;Con lo que slo ocupo lugar en el stack para pasarle la direccin de la misma. Luego en la funcin, como todos los miembros de la estructuras son accesibles por medio del puntero, tengo pleno control de la misma.Un ejemplo de funciones ya usadas que poseen como parmetros a punteros son:scanf(puntero_a_string_de_control , punteros_a_variables) printf(puntero_a_string_de_control , variables )En ambas vemos que los strings de control son , como no podra ser de otro modo , punteros , es decir que los podramos definir fuera de la funcin y luego pasarselos a ellas :p_control = "valor : %d " ; printf( p_control , var ) ;PUNTEROS COMO RESULTADO DE UNA FUNCIONLas funciones que retornan punteros son por lo general aquellas que modifican un argumento , que les ha sido pasado por direccin ( por medio de un puntero ) , devolviendo un puntero a dicho argumento modificado , las que reservan lugar en el Heap para las variables dinmicas , retornando un puntero a dicho bloque de memoria .As podremos declarar funcines del tipo de:char *funcion1( char * var1 ) ; double *funcion2(int i , double j , char *k ) ; struct item *funcion3( struct stock *puntst ) ;El retorno de las mismas puede inicializar punteros del mismo tipo al devuelto , distinto , por medio del uso del casting . Algunas funciones , tales como malloc() y calloc() definen su retorno como punteros a void :void *malloc( int tamano ) ;de esta forma al invocarlas , debemos indicar el tipo de puntero de deseamosp = (double *)malloc( 64 ) ;

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 encompartimientos, 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 otroscompartimientos 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.

Si en nuestro archivo pudisemos almacenar un mximo de 20.000 hojas, esta sera la capacidad de nuestra memoria (unos 19 Kilobytes). Estas hojas de nuestros informes las agruparamos de distintas formas. Quiz un informe slo ocupe 5 pginas mientras que otro puede ocupar 100. Podemos ver esto como los distintos tipos dedatos del C, es lgico pensar que necesitamos ms espacio para almacenar un nmero real que uno entero o que una matriz de 20x20 elemento. Estos son nuestros informes en nuestro archivo. Sin embargo los punteros siempre ocupan lo mismo, en nuestro ejemplo nos llegara con una pgina para poder escribir el nmero del compartimiento en el que se encuentra el inicio del informe.

As en nuestro supuesto de que slo trabajemos con tres informes a la vez, dispondramos de tres compartimientos en los que indicaramos dnde se encuentran esos informes que buscamos y de esta forma cuando terminemos con ellos y deseemos trabajar con otros slo tendremos que cambiar el contenido de esos tres compartimientosdiciendo donde se encuentran los nuevos informes. De esta forma no es necesario reservar unos compartimientos para trabajar y cada vez que cambiemos de trabajo llevar los informes viejos a su compartimiento anterior y traer los nuevos informes a estos compartimientos.

Esto es lo que en programacin se conoce como referencia indirecta o indirecin. Accedemos a la informacin a travs de un puntero que nos dice dnde se encuentra sta. Y a grandes rasgos esto son los punteros, referencias indirectas a datos en la memoria del ordenador.

Los punteros en C son muy importantes puesto que su utilizacin es bsica para la realizacin de numerosas operaciones.Entre ellas: paso de parmetros que deseamos sean modificados, tratamiento de estructuras dinmicas de datos (esto es, variables que no se declaran en el programa y se crean durante la ejecucin del programa), cadenas de caracteres ...

Operadores que actan sobre punteros.

El lenguaje C proporciona dos operadores relacionados directamente con los punteros. El primero de ellos es el operador &. Ya hemos visto este operador antes en las llamadas a la funcin scanf, posteriormente explicaremos por que la funcin scanf necesita ser llamada con el operador &.

El operador &, es un operador unario, es decir, acta sobre un slo operando. Este operando tiene que ser obligatoriamente una estructura direccionable, es decir, que se encuentre en la memoria del ordenador. Estas estructuras son fundamentalmente las variables y las funciones, de las que hablaremos posteriormente. Decimos queslo se puede aplicar sobre estructuras direccionables porque su funcin es devolver la posicin de memoria en la que se encuentra dicha estructura. En nuestro ejemplo nos indicara cual sera el compartimiento en el que se encuentra el informe que le indiquemos.

El segundo operador es el *. Tambin se trata de un operador unario como el anterior y su funcin en este caso es la de permitir el acceso al contenido de la posicin indicada por un puntero. En nuestro ejemplo el operador * nos permitira leer o escribir elinforme al que apunta uno de nuestros compartimientos punteros. Adems el carcter * se utiliza para declarar punteros los cuales como ya dijimos tienen que ser declarados (tienen su propio compartimiento en el archivo).

Por supuesto el operador * debe ser aplicado sobre un puntero, mientras que el operador & sobre una estructura direccionable (variable o funcin). Veamos un ejemplo de su utilizacin:

main () { int x,y; /* Variables de tipo entero */ int *px; /* Puntero a una variable de tipo entero */

/* Leemos la direccin -compartimiento- de la variable-informe- x mediante & y lo almacenamos en la variable punteropx */ px = &x; /* px contiene la direccin en la que se encuentra x */ /* Utilizando el operador *, podemos acceder a suinformacin. *px representa ahora el valor de la variable x */ *px = 10; /* Ahora x contiene el valor 10 */ y = 15; /* Si ahora hacemos que nuestro puntero apunte a lavariable y utilizando de nuevo el operador & */ px = &y; /* El valor que ahora toma *px ser el valor de y puestoque es el compartimiento al que ahora estamos apuntando */ *px = 125; /* Ahora y contiene el valor 125 */ x = *px /* Ahora x contiene tambin 125 */ }

Como hemos visto en este ejemplo es exactamente igual acceder a una variable que utilizar un puntero que apunte a ella (hacemos que apunte a ella mediante el operador &) junto con el operador *.

Pero el lenguaje C an ofrece otra herramienta ms para trabajar con punteros. Es lo que se suele llamar aritmtica de punteros. Este tema lo trataremos en profundidad en el siguiente apartado.

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 muysencillo 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 comopginas 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 punteropor 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.

Supongamos que hemos definido un tipo de datos en nuestro programa que fuese pgina, si cada pgina puede contener 80 caracteres de ancho por 25 de alto, podra ser algo como sto:

typedef char pgina[80][25];

Y supongamos tambin que slo tenemos tres tipos de informes, de 1 pgina, de 5 pginas y de 25 pginas:

typedef pgina informe1; typedef pgina informe2[5]; typedef pgina informe3[25];

Y en nuestro programa principal hemos declarado las siguientes variables:

main() { pgina *punt_pgina; informe1 i1[10],*punt1; informe2 i3[5],*punt2; informe3 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 decaracteres 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];

Y por ser en esencia una matriz todo lo comentado anteriormente para matrices y punteros puede ser aplicado a ellas.As la siguiente definicin constituye tambin una cadena de caracteres:

char *identificador;

La diferencia entre ambas declaraciones es que la primera reserva una zona de memoria de tamao_de_la_cadena para almacenar el mensaje que deseemos mientras que la segunda slo genera un puntero.

La primer por tratarse de una matriz siempre tiene un puntero asociado al inicio del bloque del tamao especificado. Podemos tratar a las cadenas como punteros a caracteres (char *) pero tenemos que recordar siempre que un puntero no contiene informacin slo nos indica dnde se encuentra sta, por tanto con la segundadefinicin no podramos hacer gran cosa puesto que no tenemos memoria reservada para ninguna informacin. Veamos un ejemplo para comprender mejor la diferencia entra ambas declaraciones.

Utilizaremos dos funciones especiales de stdio.h para trabajar con cadenas. Estas son puts y gets que definiramos como un printf y un scanf exclusivo para cadenas.

#include main() { char cadena1[10]; char cadena2[10]; char *cadena;

gets(cadena1); /* Leemos un texto por teclado y lo almacenamos en cadena 1 */ gets(cadena2); /* Idem cadena2 */

puts (cadena1); /* Lo mostramos en pantalla */ puts (cadena2);

cadena = cadena1; /* cadena que slo es un puntero ahora apunta a cadena1 en donde tenemos 10 caracteres reservados por la definicin */

puts (cadena); /* Mostrara en pantalla el mensajecontenido en cadena1 */ cadena = cadena2; /* Ahora cadena apunta a la segundamatriz de caracteres */ gets(cadena); /* Cuando llenos sobre cadena ahoraestamos leyendo sobre cadena2, debido al efecto de la instruccinanterior */ puts(cadena2); /* SI imprimimos ahora cadena2 la pantallanos 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 allenguaje 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 ensubprogramas 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 decontrol 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 funcinrealiza 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 cdigoque 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.

Estas variables solamente podrn ser accedidas dentro de la funcin, esto es, entre las llaves ({}). Los nombres de las variables locales pueden ser los mismos en distintas funciones puesto que slo son accesibles dentro de ellas. As si estamos acostumbrados a utilizar una variable entera llamada i como contador en nuestro bucles, podemos definir en distintas funciones esta variable y utilizarla dentro de cada funcin sin que haya interferencias entre las distintas funciones.

Con respecto al cdigo de la funcin, pues simplemente se trata de un programa como todos los que hemos estado haciendo hasta ahora.

La instruccin return del final puede omitirse si la funcin no devuelve ningn valor, su cometido es simplemente indicar que valor tomara esa funcin con los parmetros que le hemos pasado. En otros lenguajes las funciones que no devuelvenvalores se conocen como procedimientos.

Veamos un ejemplo de definicin de una funcin.

int busca_elemento (int *vector,int valor,int longitud) { int i;

for (i=0;i