Está en la página 1de 17

Procedimientos, Funciones y Recursividad

Gonzalo Soriano gsorianob@gmail.com 9 de junio de 2009

Divide y vencers a

1.

Introduccin a procedimientos y funciones. o

Un procedimiento o funcin es un bloque de cdigo que no se encuentra en o o el bloque o programa principal; pero puede ser invocado por ste cuantas veces e quiera el programador. Cuando tenemos que resolver un gran programa, muchas veces es muy util di vidirlo en varios pequeos problemas; de esta forma resolvemos ms problemas, n a pero ms sencillos. a Tambin es muy util usar procedimientos y funciones cuando una tarea la tene emos que realizar varias veces; de esta forma, la implementamos una vez y la invocamos cuantas veces sea necesario. Por ejemplo; si tenemos que desarrollar un programa de lgebra, es muy probable que para distintos problemas necesia tamos calcular la norma de un vector, o el determinante de una matriz. En este caso podemos hacer una funcin que ser llamada cuando se la necesite. o a

1.1.

Funciones

La estructura de una funcin es: o function nombre_funcion (param1:tipo1; ... ; paramN:tipoN): Tipo_retorno; var { Bloque de declaracin de variables locales a la funcin. } o o { El mbito donde se pueden usar estas variables es solo a } { entre el begin y end que marcan el comienzo y fin de la } { misma. } begin { Bloque de cdigo de la funcin. } o o nombre_funcin := valorRetornoTipoRetorno; o { Esta ltima lnea debe ejecutarse si o si antes de llegar } u { al final de la funcin, no necesariamente justo antes. o } end; Donde nombre_funcion ser el nombre que usemos para indicarle a Pascal a que queremos que ejecute el cdigo de la funcin. Tipo_retorno tiene que ser o o un tipo de dato atmico (boolean, integer, real, char, etc), el cual tiene que ser o del mismo tipo que se le asigne a la funcin con valorRetornoTipoRetorno. o Y Bloque de cdigo de la funcin son las sentencias para que la funcin o o o cumpla con el objetivo con el que fue creada. La cantidad de parmetros (variables) pasados a la funcin van desde cero hasta a o los permitidos por la capacidad de la memoria. Los tipos de estos parmetros, a a diferencia del Tipo_retorno, pueden ser de cualquier tipo, incluso tipos compuestos. Cuando en la funcin hacemos: nombre_funcin := valorRetornoTipoRetorno; o o le estamos asignando un valor a esa funcin para que devuelva, pero hay que o tener en cuenta que una vez que le asignamos ese valor no se le puede cambiar; por lo menos por esa llamada.

1.1.1.

Pasaje de parmetros por valor y referencia a

Existen dos formas de pasarle los parmetros a las funciones; por valor y por a referencia. Cuando pasamos un parmetro por valor el compilador crea una a copia exacta (para esto necesitamos ms memoria) y se la pasa a la funcin; de a o forma que si lo modicamos dentro de la funcin, esas diferencias no se ver o an fuera de ella. Cuando pasamos un parmetro por referencia el compilador a crea una especie de apuntador a la variable original; por lo que cualquier modicacin se reejar en el bloque de cdigo que lo invoco. Para pasar una variable o a o por referencia hay que anteponer la palabra reservada var a la variable; de la forma: (var param:tipo-parametro);. Las variables usadas en la seccin bloque de cdigo de la funcin pueden ser o o o las pasadas por parmetros y/o las variables locales a la funcin. En caso de a o usar una variable declarada para el programa principal y que no sea pasada por parmetros se dice que estas usando una variable global; cosa prohibida por la a ctedra. a

1.1.2.

Usos de las funciones

Para invocar la funcin es suciente con poner el nombre de la funcin y o o pasarle los parmetros necesarios; es importante recalcar que se deben pasar la a misma cantidad parmetros y del mismo tipo que fueron declarados cuando se a deni la funcin. No es necesario que tengan el mismo nombre. o o Como las funciones retornan un valor, es posible (no obligatorio), asignarle ese valor a una variable o usarlo en una expresin. o program ejemplo_funciones; uses crt; var { Variables globales a las que se puede acceder desde } n, entero: integer; { cualquier parte del programa. } function ejemplo (n : integer) : integer; begin ... end; { Programa Principal } begin ... { Llamo a la funcin y guardo el resultado en la variable entero. } o entero := ejemplo(n); { Llamo a la funcin sin guardar el resultado. } o ejemplo(n); { Llamo a la funcin pasndole el nmero 5. } o a u n := ejemplo (5);

{ Llamo a la funcin pasndole una variable con nombre o a { distinto al puesto en la definicin de la funcin. o o n := ejemplo(entero); { Uso la funcin en una expresin. } o o if ( 7 = ejemplo() ) then ... end.

} }

Una posibilidad para asegurarse que no estn usando accidentalmente una a variable global en el mbito de una funcin (problema que puede generar noches a o sin sueo por no encontrar un bug cerca de una entrega) es ubicar las variables n del programa principal despus de las funciones, y justo antes del programa e principal.

program ejemplo_funciones; uses crt; function ejemplo (n : integer) : integer; begin ... end; var { Variables globales a las que se puede acceder solo } n, entero: integer; { en el Programa Principal. } { Programa Principal } begin ... entero := ejemplo(n); ... end. 1.1.3. Parmetros actuales y parmetros formales a a

Los parmetros formales son aquellos que, como el nombre lo indica, le a o o dan forma a la funcin. Es decir, son aquellos que aparecen en su denicin y se usan para indicar la cantidad y tipos de parmetros que va a recibir la funcin. a o Por ejemplo:

function nombre (param_formal1:tipo1; ... ; param_formalN:tipoN): tipo; begin ... end; Los parmetros actuales son los que se estn usando actualmente en la a a ejecucin del programa. Estos parmetros deben coincidir en su tipo, cantidad o a 4

y orden a los denidos en el encabezado de dicha funcin, ya que son los que o ocuparan el lugar reservado por los parmetros formales. a

1.1.4.

Ejemplo

program expo; uses crt; var n: integer; x: real; { Funcion que multiplica |n| veces a x, y si n era negativo, lo invierte. Le paso por valor x y n; y retorna un real. } function exponencial (x: real; n: integer):real; var i, modulo : integer; resultado : real; begin resultado :=1; { Le calculo el modulo a n. } modulo := abs(n); 5

{ Multiplico x las |n| veces. } for i:=1 to (modulo) do resultado := resultadox; { Si n era negativo, lo invierto. } if (n<0) then resultado := 1 / resultado; { Retorno el resultado en exponencial. } exponencial := resultado; end; begin { Limpio la pantalla. } clrscr; { Imprimo mensajes y leo las variables. } writeln(Programa que calcula x a la n, con n entero); writeln; write (Ingrese x: ); readln (x); write (Ingrese n: ); readln (n); { Llamo a la funcion exponencial, pasandole como parametros x y n, y guardando el valor de retorno en x. } x := exponencial (x, n); { Imprimo el resultado y espero que ingresen una tecla. } writeln (El resultado es: ,x :0:2); readkey; end.

1.1.5.

Seguimiento de la funcin o

Suponiendo que el usuario ingresa 3.5 para x y 2 para n: Prog Ppal. n 2 x 3.5 x 3.5 n 2 Funcin exponencial o res 1 3,5 12.25 i 1 2 exponencial Prog Ppal. n 2 x 3,5 12.15

12.5

1.2.

Procedimientos

Si necesitamos una funcin que no retorne nada, usamos un procedimiento; o su estructura es: procedure nombre_procedimiento (param1:tipo1; ... ; paramN:tipoN); var { Bloque de declaracin de variables locales al proc. } o begin { Sentencias del procedimiento. } 6

end;

1.3.

Diferencias entre funciones y procedimientos

Hay que tener en cuenta que ahora que ya no tenemos la sentencia nombre_funcin := TipoRetorno; o y en el encabezado de la funcin cambiamos la palabra reservada function por o procedure, y eliminamos la parte ": Tipo_retorno". Otra diferencia con las funciones es que ya no se puede usar en las expresiones.

1.4.

Usos de los procedimientos

Para invocar el procedimiento solo tenemos que poner su nombre y pasarle los parmetros necesarios. Como los procedimientos no retornan un valor, no a es posible usarlo en una expresin. o program ejemplo_proc; uses crt; var cadena: string;

procedure ejemplo (linea : string); begin ... end; { Programa Principal } begin ... { Llamo al procedimiento. } ejemplo(cadena); end.

2.

Recursividad.

Se dice que algo es recursivo cuando en su denicin se usa lo que estamos o tratando de denir. Por ejemplo, el factorial: 1 n (n 1)! si n = 0 si n > 0

n! =

En este caso denimos el factorial de n, como n por el factorial de (n-1); si n es distinto de 0; y 1 para n=0.

2.1.

Estructura de una funcin o procedimiento recursivo o

Una funcin recursiva siempre tiene dos partes fundamentales; la condicin o o de corte y la llamada recursiva. La llamada recursiva va a ser la que va a invocar nuevamente a la funcin para que se siga ejecutando. En cambio, la o condicin de corte, va a ser la encargada de frenar esa recursividad. o Generalmente, esa condicin de corte est asociada a la estructura if, pero o a puede darse el caso en que sea conveniente usar otra estructura selectiva; como por ejemplo, un case. A su vez, cuando llega a esa condicin de corte suele o inicializarse alguna variable, o preparar el ambiente para que se d el retroceso, e pero tampoco es una regla que se debe cumplir siempre.

Hay que tener en cuenta que cuando se invoca a un procedimiento recursivo, no solo se necesita espacio en memoria para l, sino tambin para todas sus llae e madas recursivas. Por ejemplo, si queremos calcular recursivamente el factorial de 1,000, vamos a necesitar 4 bytes para el valor de n. Pero como no sabemos el valor del factorial de 999, vamos a llamar a la funcin para que nos calcule el o valor de ese factorial; y as sucesivamente hasta que lleguemos a pedir el facto rial de 0. Por lo tanto, en algn momento, en memoria van a coexistir las 1,001 u llamadas a la funcin factorial, y que, si ocupa 4 bytes cada variable entera, o estar amos ocupando 4,004 bytes. Es un nmero despreciable para los tamaos u n de la memoria de ahora, pero tengamos en cuenta que eso fue porque comenzamos con un procedimiento que tan solo necesitaba 4 bytes para almacenar sus variables. Como conclusin, hay que tener cuidado con la cantidad de memoria o que necesitemos en una funcin recursiva ya que puede crecer rpidamente. o a

2.2.

Seguimiento de una funcin recursiva o

Aprovechando que ya pusimos el cdigo del factorial y que es una funcin o o conocida por todos, calculemos (recursivamente) el factorial de 5. Al ver el encabezado de la funcin nos damos cuenta que tenemos que pasarle un o parmetro n que ser el nmero del cual queremos obtener el factorial, entonces a a u hacemos f actorial(5);

Pero ahora tenemos el problema que para calcular el factorial de 5, necesitamos el factorial de 4, entonces usamos la funcin factorial para saber ese valor: o f actorial(4);

Esperamos a que termine el f actorial(4); pero nos encontramos nuevamente con que no sabemos cuanto vale el factorial de 3, entonces le pedimos a alguien que si lo cepa que nos lo calcule: f actorial(3);

Creo que no hace falta que lo diga, pero por las dudas, ahora no sabemos cuanto vale el factorial de 2, entonces esperemos y pidamosle a alguien que haga ese trabajo por nosotros: f actorial(2);

Y si lo hicimos tantas veces, porque no una vez ms; f actorial(1); a

Pero seguimos sin saber cuanto es el factorial de 1, por lo que invocamos nuevamente a la funcin factorial, pero ahora le pasamos un 0: f actorial(0); o

Y ahora si nos preguntaron algo que si sabemos!!, cunto es el factorial de 0?. a

10

La respuesta es 1, como lo dice la condicin de corte; por lo que dejamos de o llamar recursivamente a la funcin factorial y le devolvemos el valor pedido a o quien nos lo pidi. o A partir de ahora vamos a ir volviendo nuestros pasos para atrs e ir terminando a cada una de las funciones que empezamos.

Con ese valor, ahora vamos a poder calcular el factorial de 1, que era 1 f actorial(0) = 1 1 = 1

11

Recin ahora que tenemos cuanto vale el factorial de 1, se lo devolvemos a quien e nos lo hab pedido: a

Con el valor del factorial de 1, podemos calcular el factorial de 2 y devolvrselo e a quien nos lo hab pedido: a

12

Con el valor del factorial de 2, podemos calcular el factorial de 3 y devolvrselo e al factorial de 4 para que siga con su ejecucin: o

Ya casi terminamos, ahora con el valor del factorial de 3, calculamos el de 4 como: f actorial(4) = 4 f actorial(3) = 4 6 = 24

13

Y nalmente llegamos a tener el factorial de 4, por lo que con esto solo nos queda multiplicarlo por 5 para calcular el factorial que nos hab pedido en un an primer momento:

2.3.

Tipos de Recursividad

En programacin existen dos tipos de recursividad: directa o indirecta. o

2.3.1.

Recursividad Directa

La recursividad directa es cuando un procedimiento o una funcin se llao ma a si mismas; por ejemplo: procedure ejemplo(); begin Sentencias; ejemplo(); 14

ms_sentencias; a end; 2.3.2. Recursividad Indirecta

La recursividad indirecta es cuando un procedimiento o funcin invoca o a otro procedimiento o funcin, y ste ultimo vuelve a invocar al primero. Por o e ejemplo: procedure rec2(); forward; procedure rec1(); begin Sentencias; rec2(); end; procedure rec2(); begin Sentencias; rec1(); end; Por la forma secuencial de compilar de Pascal es necesario declararle que ms a adelante se denir el procedimiento rec2 para que no marque un error en a tiempo de compilacin. Por este motivo es que tuvimos que incluir la l o nea: procedure rec2(); forward; antes del encabezado del procedimiento rec1().

2.4.

Ejemplo

program ejemRec; uses crt; procedure recDirecta (entero : integer); begin if (entero = 1) then writeln (El entero es: ,entero) else begin recDirecta (entero 1); writeln (El entero es: ,entero); end; end; function factorial (n : integer): integer; begin if (n = 0) then factorial := 1 else factorial := nfactorial (n1); end; 15

procedure B (entero : integer); forward; procedure A (entero : integer); begin if (entero = 1) then writeln (A) else B (entero1); end; procedure B (entero : integer); begin if (entero = 1) then writeln (B) else A (entero1); end; var n, fac : integer; begin clrscr; writeln (Ejemplo de funciones recursivas.); writeln; n := 5; fac := factorial(5); writeln (El factorial de ,n, es , fac,.); writeln; n := 10; writeln (Entramos a la funcion recDirecta con n = , n,.); recDirecta(n); writeln; n := 4; write(Llamado a la funcion A (,n,): ); A(n); write(Llamado a la funcion B (,n,): ); B(n); n := 5; write(Llamado a la funcion A (,n,): ); A(n); write(Llamado a la funcion B (,n,): ); B(n); readkey; end.

16

Indice
1. Introduccin a procedimientos y funciones. o 1.1. Funciones . . . . . . . . . . . . . . . . . . . . . . . 1.1.1. Pasaje de parmetros por valor y referencia a 1.1.2. Usos de las funciones . . . . . . . . . . . . . 1.1.3. Parmetros actuales y parmetros formales a a 1.1.4. Ejemplo . . . . . . . . . . . . . . . . . . . . 1.1.5. Seguimiento de la funcin . . . . . . . . . . o 1.2. Procedimientos . . . . . . . . . . . . . . . . . . . . 1.3. Diferencias entre funciones y procedimientos . . . . 1.4. Usos de los procedimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 2 3 4 5 6 6 7 7 7 7 8 13 13 14 14

2. Recursividad. 2.1. Estructura de una funcin o procedimiento recursivo o 2.2. Seguimiento de una funcin recursiva . . . . . . . . . o 2.3. Tipos de Recursividad . . . . . . . . . . . . . . . . . 2.3.1. Recursividad Directa . . . . . . . . . . . . . . 2.3.2. Recursividad Indirecta . . . . . . . . . . . . . 2.4. Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

17

También podría gustarte