funciones

12
Funciones Las funciones son un conjunto de instrucciones que realizan una tarea específica. En general toman ciertos valores de entrada, llamados parámetros y proporcionan un valor de salida o valor de retorno. Cómo definir una función Empezamos estudiando el siguiente código: # include <stdio.h> int suma; /* Esta es una variable global */ int main() { int indice; encabezado(); /* se llama a la función llamada encabezado */ for (indice = 1 ; indice <= 7 ; indice ++) cuadrado (indice); /* Llama a la función cuadrado */ final(); /* Llama a la función final */ return 0; } encabezado () /* Esta es la función llamada encabezado */ { suma = 0; /* Inicializa la variable "suma" */ printf("Este es el encabezado para el programa cuadratico \n\n"); } cuadrado (numero) /* Esta es la función cuadrado */ int numero; { int numero_cuadrado; numero_cuadrado = numero * numero; /* Esta genera el valor cuadrático */ suma += numero_cuadrado; printf("El cuadrado de %d es %d\n", numero, numero_cuadrado); } final () /* Esta es la función final */ { printf("\nLa suma de los cuadrados es %d\n", suma); }

Upload: jj-john-john-4601

Post on 23-Jul-2015

297 views

Category:

Education


0 download

TRANSCRIPT

Page 1: Funciones

Funciones

Las funciones son un conjunto de instrucciones que realizan una tarea específica. En general toman ciertos valores de entrada, llamados parámetros y proporcionan un valor de salida o valor de retorno.

Cómo definir una función

Empezamos estudiando el siguiente código:

# include <stdio.h>

int suma; /* Esta es una variable global */

int main(){ int indice; encabezado(); /* se llama a la función llamada encabezado */ for (indice = 1 ; indice <= 7 ; indice ++) cuadrado (indice); /* Llama a la función cuadrado */ final(); /* Llama a la función final */ return 0;} encabezado () /* Esta es la función llamada encabezado */{ suma = 0; /* Inicializa la variable "suma" */ printf("Este es el encabezado para el programa cuadratico \n\n");} cuadrado (numero) /* Esta es la función cuadrado */int numero;{ int numero_cuadrado; numero_cuadrado = numero * numero; /* Esta genera el valor cuadrático */ suma += numero_cuadrado; printf("El cuadrado de %d es %d\n", numero, numero_cuadrado);} final () /* Esta es la función final */{ printf("\nLa suma de los cuadrados es %d\n", suma);}

Page 2: Funciones

Note la parte ejecutable de este programa que empieza en la línea 9 con un enunciado que dice simplemente "encabezado ( ) ;", la cual es la manera de llamar a una función. El paréntesis es necesario porque el compilador C lo utiliza para determinar que se trata de una llamada a función y no simplemente una variable mal colocada. Cuando el programa llega a esta línea de código la función llamada encabezado ( ) es llamada, sus enunciados son ejecutados y el control regresa a los enunciados que le siguen a la llamada. Continuando nos encontramos con un bucle for que será ejecutado siete veces en donde está otra llamada a una función denominada cuadrado( ). Finalmente encontramos otra función llamada final ( ) que será llamada y ejecutada. Por el momento ignoraremos la variable indice en el paréntesis de la llamada a cuadrado ( ).

En seguida del programa principal podemos ver el principio de una función en la línea 18 que cumple con las reglas establecidas para el programa principal excepto que su nombre es encabezado ( ). Esta es la función que llamamos desde la línea 9 del programa principal. Cada uno de sus enunciados serán ejecutados y una vez completos el control retorna al programa principal, o mas propiamente dicho, a la función main ( ). El primer enunciado le asigna a la variable llamada suma el valor de cero ya que planeamos utilizarla para acumular la suma de los cuadrados. Como la variable llamada suma fue definida antes del programa principal está disponible para utilizarla en cualquiera de las funciones que se han definido posteriormente. A una variable definida de esta manera se el llama global y su alcance es el programa completo incluyendo todas las funciones. En la línea 21 se despliega un mensaje en el monitor y después el control retorna a la función main ( ).

En la llamada a la función cuadrado ( ), hemos agregado una nueva característica, el nombre de la variable indice dentro del paréntesis. Esta es una indicación al compilador para que cuando brinque a la función Usted desea tomar el valor de la variable indice para utlizarlo durante la ejecución de la función. Observando la función

Page 3: Funciones

cuadrado ( ) en la línea 25 encontramos otro nombre de variable encerrado entre paréntesis, la variable numero. Este es el nombre que preferimos para llamar a la variable pasada a la función cuando ejecutemos el código dentro de la función. Debido a que la función necesita saber el tipo de variable, esta se define inmediatamente después del nombre de la función y antes de la llave de apertura de la función. En la línea 26, la expresión "int numero;" le indica a la función que el valor que le ha sido pasado será una variable de tipo int. De esta manera el valor de la variable indice del programa principal pasado a la función cuadrado ( ) pero renombrada numero y disponible para utilizarse dentro de la función. Este es el estilo clásico para definir variables dentro de una función y ha estado en uso desde que fue definido por primera vez el lenguaje C. Un nuevo y mejor método está ganando popularidad debido a sus beneficios y lo discutiremos mas adelante en este capítulo.

En seguida de la llave de apertura de la función definimos otra variable llamada numero_cuadrado para utilizarla dentro de la función en sí. Establecemos la variable llamada numero_cuadrado como el cuadrado del valor almacenado en numero, después agregamos numero_cuadrado al total almacenado en suma. De la pasada lección recordará que "suma += numero_cuadrado;" tiene el mismo significado de "suma = suma + numero_cuadrado;", imprimimos el número y su cuadrado en la línea 32 y retornamos al programa principal.

Cuando pasamos el valor de la variable indice a la función debemos puntualizar lo siguiente: Nosotros no pasamos a la función la variable indice, lo que pasamos es una copia del valor, de esta manera el valor original se protege de cambios accidentales dentro de la función. Podemos modificar la variable numero como lo requiera la función cuadrado( ) y al retornar a la función principal la variable indice no ha sido modificada, de esta manera no podemos retornar un valor a la función que llama ( main ( ) ) de la función llamada (square ( ) ) utilizando este método. Encontraremos un método bien definido para retornar valores a main ( ) o a cualquier función que hace la llamada cuando estudiemos arrays y punteros. Hasta entonces la unica manera que tenemos para comunicarnos con la función que llama son las variables globales.

Continuando en la función main ( ) llegamos a la última llamada a una función denominada final ( ) en la línea 12. En esta línea llamamos a la última función que no tiene variables locales definidas, esta función despliega un mensaje con el valor almacenado en suma para finalizar el programa. El programa termina al retornar a la función main ( ) y como ya no hay nada que hacer, el programa termina.

Para obtener más de un valor será necesario recurrir ya sea a un puntero o bien a un array.

# include <stdio.h> int main() /* Este es el programa principal */{ int x, y; for( x = 0 ; x < 8 ; x++ ) { y = cuadrado(x); /* Ir para obtener el valor de x*x */ printf ( "El cuadrado de %d es %d\n", x, y ) ; }

Page 4: Funciones

for( x = 0 ; x < 8 ; ++x ) printf("El cuadrado de %d es %d\n", x, cuadrado(x)); return 0;}cuadrado(entrada) /* Función para obtener el cuadrado de "entrada" */int entrada;{ int cuadratica; cuadratica = entrada * entrada; return (cuadratica) ; /* Se asigna cuadrado() = cuadratica*/}

En la función main ( ) definimos dos enteros y empezamos un bucle en la línea 7 el cual será ejecutado 8 veces, el primer enunciado dentro del bucle es "y = cuadrado (x) ;" que representa una nueva y extraña construcción, de lo que hemos aprendido no tendremos problema para entender que la parte cuadrado(x) del enunciado es una llamada a una función denominada cuadrado ( ) tomando el valor de x como parámetro. En al línea 19 encontramos que la función prefiere llamar a la variable de entrada entrada, procede a elevar al cuadrado el valor de entrada y llamar al resultado cuadratica, después en la línea 25 tenemos un nuevo enunciado, la instrucción return. El valor dentro del paréntesis se asigna a la función en sí y se retorna como un valor utilizable en el programa principal asignandose este valor a y. El paréntesis que encierra el valor retornado en la línea 25 no es necesario pero la mayoría de los programadores C experimentados lo utilizan.

Es necesario hacer esta aclaración, el tipo de variable retornada debe declararse para darle sentido a los datos, si la variable no es declarada, el compilador la asignará como tipo int, si se desea otro tipo específico debe declararse.

Page 5: Funciones

Funciones de punto flotante

Veremos ahora un ejemplo de función de estilo clásico con retorno de punto flotante. Empieza definiendo una variable global de punto flotante llamada z que será utilizada posteriormente. Después, en la parte principal del programa se define un entero seguido de dos variables de punto flotante siguiendoles dos definiciones de extraño aspecto. Las expresiones cuadrado( ) y glcuadrado( ) en la línea 8 parecen llamadas a función. Esta es la forma adecuada para definir que una función regresará un valor que no es de tipo int sino de otro tipo, en este caso de tipo flotante. Observe que ninguna función es llamada en esta línea de código, simplemente se declara el tipo de dato que retornarán estas dos funciones.

Refiriendonos a la función cuadrado( ) que empieza en la línea 28 verá que el nombre es precedido por la palabra clave float, esto lo indica al compilador que esta función retornará un valor de tipo float a cualquier programa que las llame. El tipo de dato que retorna la función es ahora compatible con la llamada a esta función. La siguiente línea de código contiene "float valor_interno;" lo que le indica al compilador que la variable pasada a esta función desde el programa que la llama será de tipo flotante.

La función glcuadrado ( ) empieza en la línea 38 retornará una variable de tipo float pero además utiliza una variable global para la entrada. El cálculo cuadrático lo hace en el enunciado return y por lo tanto no requiere definir una variable separada para almacenar el producto. La función cuadrado ( ) pudo ejecutar el cálculo cuadrático en la instrucción return pero se hizo en forma separada a manera de ilustración.

# include <stdio.h>

float z; /* Variable global */

int main(){ int indice; float x, y, cuadrado(), glcuadrado();

for(indice = 0 ; indice <= 7 ; indice ++) { x = indice; /* convierte int en float */ /* el cuadrado de x a una variable de punto flotante */ y = cuadrado(x); printf("El cuadrado de %d es %10.4f\n", indice, y); }

for (indice = 0 ; indice <= 7 ; indice ++) { z = indice; y = glcuadrado (); printf("El cuadrado de %d es %10.4f\n", indice, y); } return 0;}

/* Eleva al cuadrado un tipo float, retorna un tipo float */

Page 6: Funciones

float cuadrado (valor_interno)float valor_interno;{ float cuadratica; cuadratica = valor_interno * valor_interno; return(cuadratica);}

/* Eleva al cuadrado un tipo float, retorna un tipo float */float glcuadrado (){ return(z * z);}

En los tres programas que hemos estudiado en este capítulo se ha utilizado el estilo clásico para definir funciones, si bien, este fue el primer estilo definido en C existe un método mas reciente que le permite detectar errores con mayor facilidad. Cuando Usted lea artículos de C se encontrará programas que utilizan el estilo clásico por lo que Usted debe estar preparado para interpretarlos correctamente, esta es la razón por lo que incluimos el estilo clásico en este tutorial sin embargo, se recomienda ampliamente que Usted adopte y use el método moderno tal y como está definido por el estándar ANSI-C, mismo que empezaremos a tratar desde este momento y hasta el final de este tutorial.

Page 7: Funciones

El enunciado return en la función main( )

En la definición original de C, todas las funciones regresaban por default una variable de tipo int a menos que el autor especificara algo diferente, como era explícitamente opcional el retorno de un valor al dejar una función, la mayoría de los programas C eran escritos de la siguiente manera:

main (){

}

Cuando el prototipado de funciones fue agregado al lenguaje ( el prototipado lo estudiaremos mas adelante ), muchos programadores suponían que la función main ( ) no retornaba nada, de esta manera utilizaban el tipo void para el retorno haciendose común la práctica de escribir la función principal como sigue:

void main (){

}

Cuando el estándar ANSI-C estuvo listo el único tipo de retorno aprovado es una variable int, esto conduce a la siguiente forma de escribir la función main ( ):

int main (){ return 0;}

Para asegurar que el código que Usted escriba sea lo mas portable posible utilice la forma arriba descrita. Aparentemente debido a la inercia en torno al uso del retorno tipo void muchos fabricantes de compiladores agregan una extensión que permita el uso de código sin modificaciones por lo que existen compiladores que soportan el retorno de tipo void pero el único método aprovado por el estándar ANSI-C es el de tipo int. Finalmente comprende Usted el motivo por el que el los programas que hemos estudiado le agregamos una línea que retorna un valor de cero al sistema operativo, esto le indica que el programa se ejecutó satisfactoriamente.

El alcance de las variables

Dedicaremos una buena cantidad de tiempo en nuestro siguiente programa cubriendo algunos tópicos nuevos, algunos no parecen ser particularmente útiles sin embargo son muy importantes por lo que es conveniente estudiarlos detenidamente. Por el momento ignore los cuatro enunciados en las líneas 1 a 4 ya que las discutiremos más adelante.

Page 8: Funciones

# include <stdio.h> /* Prototipos de intrada/salida */

void head1(void); /* Prototipo para head1 */void head2(void); /* Prototipo para head2 */void head3(void); /* Prototipo para head3 */

int count; /* Una variable global */

int main(){ register int index; /* disponible solo en main */

head1(); head2(); head3();

/* Bucle "for" principal de este programa */ for(index = 8 ; index > 0 ; index--) { int stuff; /* disponible para estas llaves */ for(stuff = 0 ; stuff <= 6 ; stuff++) printf("%d ", stuff); printf(" index es ahora %d\n", index); } return 0;}

int counter; /* Variable disponible a partir de este momento */void head1(void){ int index; /* Esta variable está disponible solo en head1 */

index = 23; printf("El valor de header1 es %d\n", index);}

void head2(void){ int count; /* Esta variable está disponible solo en head2 */ /* y desplaza a la variable global del mismo nombre */ count = 53; printf("El valor de header2 es %d\n", count); counter = 77;}

void head3(void){ printf("El valor de header3 es %d\n", counter);}

/* Resultado de la ejecución:

El valor de header1 es 23El valor de header2 es 53El valor de header3 es 770 1 2 3 4 5 6 index es ahora 80 1 2 3 4 5 6 index es ahora 7

Page 9: Funciones

0 1 2 3 4 5 6 index es ahora 60 1 2 3 4 5 6 index es ahora 50 1 2 3 4 5 6 index es ahora 40 1 2 3 4 5 6 index es ahora 30 1 2 3 4 5 6 index es ahora 20 1 2 3 4 5 6 index es ahora 1

*/

¿Qué es una variable global?

La variable definida en la línea 6 denominada conut es global porque está disponible para cualquier función en el programa y está definida antes que cualquier otra función. Está siempre disponible porque existe durante todo el tiempo en que el programa es ejecutado. Más adelante en el programa se define otra variable global llamada counter, es global pero no está disponible para la función main ( ) ya que está definida en seguida de la función main ( ). Una variable global es aquella que está definida fuera de cualquier función. Las variables globales son automáticamente inicializadas a cero cuando son definidas, por lo tanto las variables count y counter tendrán ambas el valor de cero al ser inicializadas.

Regrese a la función main ( ) y podrá ver la variable index definida como de tipo int en la línea 10, por el momento ignore la palabra register. Esta variable está solo disponible dentro de la función main ( ) porque es aquí en donde está definida, además es una variable automática, lo que significa que la variable existirá cuando la función en la cual está contenida sea invocada y termina su existencia cuando la función finaliza. Otra variable de tipo entero llamada stuff está definida dentro de las llaves del bucle for. Cualquier par de llaves puede contener definiciones de variables que serán válidas solo mientras el programa ejecuta los enunciados dentro de las llaves, por lo tanto, la variable stuff será creada y destruida 8 veces, una por cada ciclo del bucle for.

Observe la función llamada head1 ( ) en la línea 29. El uso de la palabra void lo explicaremos en breve. La función contiene una variable llamada index que no tiene nada en común con la variable del mismo nombre de la función main ( ) en la línea 10, excepto que ambas son variables automáticas. Mientras el programa no ejecute sentencias de esta función esta variable no existirá. Cuando head1 ( ) es llamada se genera la variable y cuando head1 ( ) termina su trabajo la variable llamada index de la función es eliminada por completo. Tenga en mente que esto no afecta la variable del mismo nombre en la función main ( ) porque se trata de entidades diferentes. Es importante recordar que de una llamada a la siguiente, el valor de una variable no se conserva y por lo tanto debe reinicializarse.

Variables estáticas

Al colocar la palabra clave static antes de la definición de una variable dentro de una función, la ó las variables definidas son variables estáticas y existirán de una llamada a otra en una particular función. Una variable estática es inicializada una vez al cargar un programa y nunca es reinicializada durante la ejecución del programa. Si colocamos

Page 10: Funciones

la palabra clave static antes de una variable externa hacemos la variable privada lo que significa que esta variable no será posible utilizarla con ningún otro archivo, ejemplos de esto se darán en el capítulo 14.

Utilizando el mismo nombre

La función denominada head2 ( ) contiene la definición de una variable llamada count. Aunque count ha sido definida como variable global en la línea 6, es perfectamente válido volver a utilizar el nombre en esta función pues se trata de una variable completamente nueva que nada tiene que ver con la variable global del mismo nombre ocasionando que la variable global no esté disponible dentro de la función head2 ( ).

La variable register

Una computadora puede almacenar datos en un registro o en memoria. Un registro es mucho más rápido en operación que una memoria paro hay pocos registros disponibles para uso del programador. Si en un programa existen ciertas variables que son utilizadas extensivamente, Usted puede designar que estas variables sean almacenadas en un registro para acelerar la ejecución de un programa, esto se ilustra en la línea 10. Su compilador probablemente le permita utilizar una o más variables de registro, si su compilador no le permite el uso de este tipo de variables la petición de registro será ignorada.

Prototipado de funciones

Un prototipo es un modelo de un objeto real y cuando Usted programa en ANSI-C, Usted tiene la habilidad para definir un modelo de cada función para el compilador. El compilador puede entonces usar el modelo para checar cada una de las llamadas a la función y determinar si Usted ha utilizado el número correcto de argumentos en la llamada a la función y si son del tipo correcto. El estándar ANSI-C contiene el prototipado como parte de sus recomendaciones, a lo largo de este estudio se tratará ampliamente el prototipado.

Volviendo a las líneas 2, 3, y 4 del ejemplo que estamos estudiando, tenemos el prototipo para cada una de las tres funciones contenidas en el programa. El primer void le indica al compilador que esta función en particular no tiene valor de retorno. La palabra void dentro del paréntesis le indica al compilador que esta función no tiene parámetros y si una variable fuera incluida ocurriría un error que el compilador indicara en un mensaje de advertencia.

En este momento Usted empezará a utilizar el chequeo de prototipo para todas las funciones que Usted defina. La línea 1 del programa le dice al sistema que obtenga una copia del archivo llamado stdio.h localizado en el directorio include. El archivo stdio.h contiene los prototipos para las funciones estándar de entrada/salida de tal manera que pueda ser posible checar los tipos adecuados de variables, más adelante cubriremos en detalle el directorio include.

Page 11: Funciones

Biblioteca estándar de funciones

Cada compilador viene con una serie de funciones predefinidas disponibles para su uso, estas son en su mayoría funciones de entrada/salida, de manipulación de cadenas y caracteres y funciones matemáticas. Los prototipos están definidas para Usted por el escritor de su compilador para todas las funciones incluidas en su compilador. La mayoría de los compiladores tienen funciones adicionales predefinidas que no son estándar pero que permiten al programador sacar mayor provecho de su computadora en particular, en el caso de las PC compatibles con IBM la mayoría de estas funciones permiten utilizar los servicios de la BIOS en el sistema operativo o bien escribir directamente al monitor de video o en cualquier lugar de la memoria.

Recursividad

La recursividad es otra de esas técnicas de programación que cuando las vemos por vez primera parecen muy intimidantes pero en el siguiente ejemplo descubriremos el misterio en un programa muy simple pero para propósitos de ilustración resulta excelente.

# include /* Contiene el prototipo para printf */

void count_dn(int count) ; /* Prototipo para count_dn */int main( ){ int index ; index = 8 ; count_dn(index) ; return 0 ;}

void count_dn(int count){ count -- ; printf ( "El valor de la cuenta es %d\n", count ) ; if (count > 0) count_dn(count) ; printf ( "Ahora la cuenta es %d\n", count ) ;}

/* Resultado de la ejecución:El valor de la cuenta es 7El valor de la cuenta es 6El valor de la cuenta es 5El valor de la cuenta es 4El valor de la cuenta es 3El valor de la cuenta es 2El valor de la cuenta es 1El valor de la cuenta es 0Ahora la cuenta es 0Ahora la cuenta es 1

Page 12: Funciones

Ahora la cuenta es 2Ahora la cuenta es 3Ahora la cuenta es 4Ahora la cuenta es 5Ahora la cuenta es 6Ahora la cuenta es 7*/

La recursividad no es otra cosa más que una función que se llama a sí misma, es por lo tanto un bucle que debe tener una manera de terminar. En el programa, la variable index es colocada en 8 en la línea 8 y es utilizada como el argumento de la función llamada count_dn ( ). La función simplemente decrementa la variable, despliega un mensaje, y si la variable es mayor que cero, se llama a sí misma donde decrementa la variable una vez más, despliega un mensaje, etc, etc,etc. Finalmente la variable alcanza el valor de cero y la función ya no se llama a sí misma, en lugar de esto retorna al punto previo a su llamada, y retorna de nueva cuenta, y de nuevo, hasta que finalmente retorna a la función main ( ) y de aquí retorna al sistema operativo. Para que le resulte más claro piense como si tuviera ocho funciones llamadas count_dn disponible y que llama una a la vez manteniendo un registro de en cual copia estuvo en determinado momento, esto no es en realidad lo que sucede en el programa pero a manera de comparación resulta útil para comprender el funcionamiento del programa.

Cuando Usted llama a la función desde la misma función, esta alamacena todas la variables y demás datos que necesita para completar la función en un bloque interno. La siguiente vez que es llamada la función hace exactamente lo mismo creando otro bloque interno, este ciclo se repite hasta alcanzar la última llamada a la función, entonces empieza a regresar los bloques utilizando estos para completar cada llamada de función. Los bloques son almacenados en una parte interna de la computadora llamada stack, esta es una parte de la memoria cuidadosamente organizada para almacenar datos de la manera ya descrita.

Al utilizar la recursividad es posible que Usted desee escribir un programa con recursividad indirecta, opuesta a la recursividad directa descrita arriba. La recursividad indirecta puede ser cuando una función A llama a una función B, la cual a su vez llama a la función A, etc. Esto es completamente permisible ya que el sistema tomará cuidado de almacenar en stack los datos para regresarlos cuando sea necesario. Recuerde que en la recursividad, en algún punto algo debe llegar a cero o alcanzar un punto predefinido para terminar el bucle. Si esto no es así, Usted tendrá un bucle infinito, en determinado momento el stack se saturará resultando en un mensaje de error y terminando el programa abruptamente.