Introducción a la programación Tema 4 : Funciones Sergi Jordà Curso de postgrado “Programación Orientada al Multimedia” Institut Universitari de l’Audiovisual Universitat Pompeu Fabra Corrección día anterior var num_lineas as entero var n as entero print “introduce número de líneas mayor que 2” num_lineas ß input_num num_lineas ß num_lineas-1 print “**********” for n=2 to num_lineas do print “* *” end do print “**********” • Si no indicásemos que debe ser mayor que 2 deberíamos escribir unas cuantas instrucciones adicionales . Se deja como ejercicio opcional… Más… var adivina tipo entero var entrada tipo entero var intentos tipo entero adivina ß random(20) print “introduce un número entre 0 y 20” entrada ßinput_num intentos ß1 while entrada<>adivina do if entrada < adivina then print “mi número es mayor” else print “mi número es menor” endif intentos ßintentos+1 print “introduce un número entre 0 y 20” entrada ßinput_num end while print “lo adivinaste en “,intentos,” intentos !” Introducción • • • Hasta ahora hemos realizado programas sencillos pero autónomos En muchos casos, interesa crear fragmentos de programa que se puedan ejecutar en diferentes ocasiones En los programas que hemos visto hasta ahora, hay varios fragmentos que podrían ser buenos candidatos: § Calcular el valor absoluto § Calcular precio de fotocopias § Validar o acotar un número introducido por el usuario por teclado § …… • • El nombre dado a estos fragmentos variará de un lenguaje a otro. Nosotros los denominaremos funciones Para que las funciones creadas a partir de los candidatos anteriores fuesen suficientemente flexibles, deberían…..???????? Entradas de una función • Para que una función sea flexible y se pueda usar en ocasiones diferentes, utiliza lo que se denomina parámetros de entrada (pueden ser varios, uno o ninguno…) • Entradas de: § Valor absoluto? § Acotar valor numérico? § Precio fotocopias? Número a calcular Cotas inf. y sup. Número de fotocopias 1 Entradas de una función • Para que una función sea flexible y se pueda usar en ocasiones diferentes, utiliza lo que se denomina parámetros de entrada (pueden ser varios, uno o ninguno…) Salidas de una función • Para que una función sea “más flexible • § Valor absoluto? § Acotar valor numérico? § Precio fotocopias? • Entradas de: § Valor absoluto? § Acotar valor numérico? § Precio fotocopias? 1: Número a calcular 2: Cotas inf. y sup. 1: Número de fotocopias Salidas de una función • Para que una función sea “más flexible En este esquema se simboliza la función como una “caja negra”. No importa como está escrita, lo que importa es conocer sus entradas , su funcionamiento y la salida que produce El valor absoluto El valor validado El precio final Limitaciones de la salida • • • A partir de lo expuesto, podemos simbolizar una función de la siguiente forma todavía” suele disponer de una salida (sólo una, aunque en algunos lenguajes esto se pueda “trampear”) Salidas de: § Valor absoluto? § Acotar valor numérico? § Precio fotocopias? Limitaciones de la salida En el caso de los precios de las fotocopias , donde claramente podíamos desear 2 salidas (precio sin IVA, IVA), se percibe la limitación de la salida UNICA. Sin embargo, esto es así en todos los lenguajes (salvo “trucos ” que mencionaremos más adelante). ¿Porqué? • Para poder utilizar las funciones de la siguiente forma: ß funcion (a,b…) Es decir utilizando el resultado en otras expresiones • Ejemplo valor absoluto: var x tipo entero ….. x ß abs(x) Número a calcular Cotas inf. y sup. Número de fotocopias Esquema de una función • • todavía” suele disponer de una salida (sólo una, aunque en algunos lenguajes esto se pueda “trampear”) Salidas de: • En el caso de los precios de las fotocopias , donde claramente podíamos desear 2 salidas (precio sin IVA, IVA), se percibe la limitación de la salida UNICA. Sin embargo, esto es así en todos los lenguajes (salvo “trucos ” que mencionaremos más adelante). ¿Porqué? Para poder utilizar las funciones de la siguiente forma: ß funcion (a,b…) Es decir utilizando el resultado en otras expresiones Ejemplo valor absoluto: var x tipo entero ….. x ß abs(x) 2 Uso de funciones (2) Uso de funciones • • x ß menor (a,b) -- se le pasan 2 variables y el --resultado se guarda en una nueva variable Una llamada a una función se realizará invocando el nombre de esta función e incluyendo entre paréntesis los parámetros que necesita (aunque esta síntaxis puede variar de un lenguaje a otro) nombre_funcion(param1,param2,…,paramN) x ß menor (5,3) -- se le pasan 2 constantes y el --resultado...idem (en este caso, x valdr á 3) x ß menor (a,6) -- una variable y una cte… x ß y + menor (a,b) -- el resultado puede usarse en -- una expresión más compleja Como ejemplo, supondremos una función menor que devuelve el menor de 2 parámetros de entrada… A continuación mostraremos varias formas correctas de usarla: x ß otra_funcion(menor(a,b )) -- el resultado puede incluso -- pasarse como argumento de otra funcion (en este caso, -- suponemos que otra_funcion sólo usa un par ámetro…) x ß otra_func_dif(menor(a,b),y)-- idem, pero ahora -- otra_func-dif espera 2 par ámetros PRINT menor(5,8) --se pasa directamente a la función PRINT --(que mostrar ía un 5 por pantalla…) menor(5,3) -- incluso esta línea ser ía posible , pero no tiene -- ning ún sentido , ya que aunque calculemos el menor, no -- podremos utilizarlo! Como escribir una función? Consideraciones adicionales • Hemos visto como utilizar una función que ya existe , ahora veremos como crearla. Seguiremos con la función menor… • Aunque la forma exacta de escribir una función varía mucho con el lenguaje, utilizaremos la siguiente forma: funcion menor(x tipo real, y tipo real) tipo real var resultado tipo real Comenzamos con la palabra funcion y a continuación el nombre que le queramos dar (e.g. menor) if x<y then Se indican los parámetros de entrada y el tipo de cada resultado ßx uno de ellos (los nombres de estos parámetros NO else resultado ßy CONDICIONAN en absoluto los nombres de las endif variables que se pueden usar al llamar a la función, que podrán ser cualquiera… Es decir aquí ponemos devolver resultado por ejemplo x e y, pero después podemos usarla con end funcion • • Una función puede no devolver nada En este caso, se omite la última parte de la primera línea y la línea con devolver funcion pepito(x tipo entero) -- nada más …. end funcion En este caso, una llamada del tipo x ß pepito(a) sería incorrecta, ya que no se puede asignar a x algo que no vale nada menor(a,b), por ejemplo… Al final de la primera línea se indica el tipo de dato que devuelve la función Esta función sólo se puede utilizar de la forma… pepito(a) En la penúltima línea se devuelve un valor (que debe ser del mismo tipo que el indicado en la primera línea) Tiene utilidad una función que no devuelve nada? Tiene utilidad una función que no devuelve nada? • Por ejemplo, en la supuesta función escribir_fichero(nombre_fichero, dato), está bastante claro que el interés principal de ésta, radica en escribir en un fichero, no en lo que nos pueda devolver • Por ejemplo, en la supuesta función escribir_fichero(nombre_fichero, dato), está bastante claro que el interés principal de ésta, radica en escribir en un fichero, no en lo que nos pueda devolver • Aún así, es muy frecuente que este tipo de funciones también devuelvan algo. ¿Como qué? • Aún así, es muy frecuente que este tipo de funciones también devuelvan algo. ¿Como qué? • Por ejemplo un código de error que nos indique si todo ha ido bien o el tipo de error que se hubiera producido • Por ejemplo un código de error que nos indique si todo ha ido bien o el tipo de error que se hubiera producido NB. Que una función devuelva un valor NO nos obliga a utilizarlo NB. Que una función devuelva un valor NO nos obliga a utilizarlo • • Es decir, que si somos muy “confiados ” (i.e. confíamos en que escribirá en el fichero sin problemas ), en nuestro programa podemos escribir escribir_fichero(usuarios,registro) Aunque sería más precavido algo así: cod_error ßescribir_fichero(usuarios,registro) NB. Las funciones que como ésta manejan perífericos son propensas a errores . Podría suceder que: § El fichero no exista § El disco esté lleno § El fichero esté protegido contra escritura § … Es decir, que si somos muy “confiados ” (i.e. confíamos en que escribirá en el fichero sin problemas ), en nuestro programa podemos escribir escribir_fichero(usuarios,registro) Aunque sería más precavido algo así: cod_error ßescribir_fichero(usuarios,registro) NB. Las funciones que como ésta manejan perífericos son propensas a errores . Podría suceder que: § El fichero no exista § El disco esté lleno § El fichero esté protegido contra escritura § … 3 Más consideraciones • • • • Salvo casos específicos, no es conveniente que una función pida datos de teclado, muestre datos o mensajes por pantalla , etc. ¿Porqué? Este tipo de interacción con el usuario limita mucho su uso Por ejemplo una función menor que en lugar de tomar dos parámetros, no tomara ninguno y los pidiera al usuario sería muy incomoda y poco flexible… Más consideraciones • • • • Ejemplo: Datos teclado validados Más consideraciones (2) • Una función que pide un dato y lo valida • sería una clara excepción a lo dicho anteriormente, ya que el objetivo de esta función es precisamente el de pedir un dato! A continuación se escribe una posible función que pide un dato númerico al usuario y confirma que se mantenga entre unos márgenes correctos funcion input_num_acotados(menor tipo entero, mayor tipo entero) tipo entero var entrada tipo entero entrada ßinput_num while entrada<menor or entrada>mayor do entrada ßinput_num end while devolver entrada end funcion Ejemplo de uso: var mes as entero print “introduce el mes” mes ß input_num_acotados(1,12) Variables globales Variables locales • En el ejemplo anterior, hemos declarado • • una variable dentro de la función (var entrada) Este tipo de variables se denominan variables locales Son propias de la función. Sólo existen dentro de ella, y no plantean ningún conflicto con otra variable que se llame igual y que esté declarada fuera de la función Salvo casos específicos, no es conveniente que una función pida datos de teclado, muestre datos o mensajes por pantalla , etc. ¿Porqué? Este tipo de interacción con el usuario limita mucho su uso Por ejemplo una función menor que en lugar de tomar dos parámetros, no tomara ninguno y los pidiera al usuario sería muy incomoda y poco flexible… • El caso contrario, son las variables globales, que pueden ser accesibles desde cualquier lugar de un programa, inclusive dentro de las funciones de éste • En caso de coincidencia de nombre, casi todos los lenguajes dan prioridad a las variables locales Es decir si en el programa en que usamos la función input_num_acotado existiera una variable global con el nombre entrada, dentro de input_num_acotado, entrada seguirá haciendo referencia a la variable local 4 Variables globales NO • El uso de variables globales está muy desaconsejado (aunque las limitaciones de algunos lenguajes como Flash obliguen a usarlas ) • Una variable global hace que un programa sea mucho menos flexible y más difícil de modificar Si hacemos que una función dependa de una variable global, esta función no podrá ser utilizada en otro programa a no ser que también declaremos en él esta variable Si queremos que una función tenga acceso a unas variables que están en otro lugar del programa, lo ideal es que las reciba como parámetros • • • • Modificación de parámetros • En la mayoría de lenguajes, la modificación de parámetros dentro de una función, no los altera fuera de ella • A continuación mostramos un ejemplo que lo ilustra La declaración de variables globales varía de un lenguaje a otro Por ello y por su no-conveniencia, no daremos más indicaciones Función Sumatorio funcion sumatorio (n tipo entero) tipo entero var resultado tipo entero resultadoß0 while n>=1 do resultadoßresultado+n nßn-1 end while devolver resultado end funcion • En este ejemplo, queda claro que al final, n valdrá 0, pero esto no afecta a la variable que se pasó como parámetro fuera de la función var x tipo entero print “introduce un número” xßinput_num print “el sumatorio de”, x ,“es igual a :”,sumatorio(x) • Fuera de la función x no habrá cambiado! Problemas • Convertir en función, el ejercicio del día anterior (líneas de *******), de forma que la función reciba el número de líneas a dibujar • Escribir una función mayor que devuelve el mayor de dos parámetros • Escribir la función valor absoluto • Escribir una función que dado un radio calcule el área de un círculo (area=Πr2) • Escribir la función factorial (el factorial de 5 es 120 - 5*4*3*2*1) • Escribir una función potencia que admita 2 parámetros (base, exponente ) y devuelva el cálculo de la potencia (es decir base elevado a exponente ). Por ejemplo potencia(2,3) devolvería 8 como resultado (2*2*2) Modificación de parámetros (2) • • • • • Lo que acabamos de ver nos dará cierta tranquilidad respecto al uso de parámetros dentro de las funciones Sin embargo, en algunos casos, nos gustaría que las cosas fuesen de la otra forma Algunos lenguajes (Lingo NO - C, C++, Java… SI), permiten que sea el programador el que decida, para cada función, como tienen que hacerse las cosas En estos lenguajes, sería posible una función del tipo: intercambiar(x,y) Esta posibilidad (que se denomina paso de parámetros por referencia) es la que nos permitiría simular que una función tuviera más de 1 salida (no insistiremos más sobre este tema…) Mayor funcion mayor(x tipo real, y tipo real) tipo real var resultado tipo real if x>y then resultado ßx else resultado ßy endif devolver resultado end funcion 5 Valor absoluto funcion abs (x tipo real) tipo real if x<0 then xß-x devolver x end funcion 6