INFORMATICA – C.B.I. (Ciclo Básico de Ingeniería) - 2015 Departamento de Ciencias de la Computación – FACET / UNT Grupo II – Dictado: Ing. Juan Manuel Conti.
SUBPROGRAMAS EN PASCAL. Llamaremos subprograma a un código compacto, contenido dentro de un programa, y que realiza una tarea específica como validar datos de entrada, generar recuadros, ordenar arreglos, realizar cálculos matemáticos, etc. Ud. sin saberlo ha estado utilizando estos subprogramas en forma totalmente transparente. Cuando calculaba una raíz cuadrada mediante la expresión:
Raiz:=sqrt(x) estuvo haciendo uso de la función sqrt( ) que en su esencia íntima no es otra cosa que un código ejecutable, pero con la particularidad que el mismo ya fue escrito por Borland en lugar de Ud. El valor encerrado entre paréntesis se denominaba un argumento o parámetro pasado a la función, y el prototipo de la misma (solicitado a través del help) indicaba las características de este parámetro y el valor devuelto por la función:
function Sqrt( x : real): real; Esto significaba que cualquier magnitud numérica asignada a x es convertida en un real, realiza sus cálculos y retorna en el nombre en sí de la función, un resultado (el valor de la raíz) de tipo real. Un subprograma posee una estructura similar a la de un programa básico en Pascal:
Cabecera; Bloque declarativo; begin instrucciones ejecutables; end; y este trozo de códigos debe ubicarse antes del (* main *) y en general de cualquier invocación al mismo, entendiendo por invocación o llamado, al hecho en sí de utilizar la función. En el caso anterior:
Raiz:=sqrt(x) se dice que hemos efectuado una invocación o llamada a la función sqrt( ).
Cabecera. Comienza con la palabra clave function seguida a continuación de un nombre que responda a las reglas ya vistas sobre sintaxis de identificadores. Si la función va a trabajar sobre valores que le son pasados desde el punto de invocación (parámetros), entonces el nombre va acompañado de paréntesis dentro de los cuales se enumerarán los valores que recibirá, especificando su nombre y tipo.
Clase Teórica Nro 8
Pág. 1/11
INFORMATICA – C.B.I. (Ciclo Básico de Ingeniería) - 2015 Departamento de Ciencias de la Computación – FACET / UNT Grupo II – Dictado: Ing. Juan Manuel Conti. El final de esta declarativa van dos puntos (:) y el tipo que retornará la función. Veamos un ejemplo:
function ModuloZ( Re:double; Im:double):double; La función se denomina ModuloZ (determina el módulo de un complejo Z cuyos componentes real e imaginario se conocen) y recibe dos argumentos: Re e Im de tipo double. El valor regresado por esta función será de tipo double.
Muy importante: Los nombres de estos parámetros son totalmente genéricos lo cual significa que desde el punto de invocación la función puede ser llamada con cualquier otro identificador, incluso valores escritos manualmente: Modulo:=ModuloZ(3,4) Tal vez desde otro lugar remoto del programa vuelva a requerir los servicios de esta función sólo que con otros argumentos. Piense lo siguiente: Ud. dispone de 2 vectores correspondientes a la parte real y a la parte imaginaria de una cierta cantidad de complejos y desea determinar sus magnitudes:
var
VectRe : array[1..DIM]of real; VectIm : array[1..DIM]of real; ModZ : array[1..DIM]of real; i : byte;
begin (* main *) ...................... for i:=1 to DIM do ModZ[i]:=ModuloZ(VectR[i],VectIm[i]); end; donde hemos invocado DIM veces a la función ModuloZ( ) pero con distintos argumentos. Sin embargo localmente siempre han sido recibidos con los mismos nombres Re e Im. Estos parámetros en la cabecera de la función se denominan parámetros formales y los que figuran en el punto de invocación se denominan parámetros locales. Los parámetros formales se denominan así porque establecen la forma en que dichos elementos serán recibidos, teniendo además el sentido de un verdadero bloque declarativo. Si la cantidad de estos parámetros es numerosa, puede recurrirse a la sintaxis clásica de un bloque declarativo:
function Nombre ( Parámetro1 : tipo1; Parámetro2 : tipo2; .............................. Parámetron : tipo_n ):tipo_devuelto; Estos argumentos pueden ser utilizados por el código operativo de la función como si ellos hubiesen sido declarados en bloque propio de la función.
Clase Teórica Nro 8
Pág. 2/11
INFORMATICA – C.B.I. (Ciclo Básico de Ingeniería) - 2015 Departamento de Ciencias de la Computación – FACET / UNT Grupo II – Dictado: Ing. Juan Manuel Conti. Muy importante: los parámetros locales (desde la invocación) deben corresponderse:
En cantidad. En tipo En orden con aquellos que son esperados en la declarativa formal del subprograma. Dicho en otras palabras: si la function está esperando 3 parámetros, en la invocación o llamada a la función deben enviarse 3 parámetros. Si los dos primeros deben ser enteros y el último de tipo double, deben corresponderse en ese orden. A continuación de la cabecera viene el bloque de identificadores propios que requiera el subprograma para su funcionamiento. Pueden incluir constantes y variables como cualquier programa básico:
const ............. var ............. con tantos elementos como sean necesarios. Todos estos identificadores: los parámetros formales y los del bloque declarativo, se denominan identificadores locales y tienen vida mientras la función se halle activa (o sea operando). Una vez que la función se ha extinguido porque su ejecución finalizó, todos estos identificadores se pierden, y su explicación es muy sencilla: Cada vez que una función es invocada, el compilador le asigna un espacio de memoria RAM para que la misma opere. En este espacio se almacenan tanto los parámetros formales como los identificadores del bloque declarativo, y de allí son tomados por los códigos ejecutables para las operaciones de procesamiento. Una vez finalizada la ejecución de la función esta zona de memoria es liberada perdiéndose todo lo que había en ella. Tanto los parámetros formales como los identificadores locales sólo pueden ser accesados por la propia función. A continuación del bloque declarativo se escribirán los códigos ejecutables de la función que pueden ser tan complejos como se requiera. Ahora bien, para que la función pueda retornar un valor en su propio nombre es necesario que en algún momento (generalmente al final, aunque no es obligatorio) debe existir una instrucción en la cual figure de izquierda a derecha:
NombreDeLaFunción:=Expresión; En el ejemplo del módulo: ModuloZ:=sqrt(Re*Re+Im*Im); Caso contrario la función no retornará nada.
Clase Teórica Nro 8
Pág. 3/11
INFORMATICA – C.B.I. (Ciclo Básico de Ingeniería) - 2015 Departamento de Ciencias de la Computación – FACET / UNT Grupo II – Dictado: Ing. Juan Manuel Conti. IMPORTANTE: Debe tomarse especial cuidado en no colocar el nombre de la función en el lado derecho, puesto que ello implicaría un nuevo llamado a la función en sí, creando lo que se denomina recursividad. Este es un concepto muy potente que va más allá del alcance de este curso. Cuando estudiemos otro tipo de subprogramas denominados procedimientos, analizaremos dos modalidades adicionales muy importantes en la forma de recibir los parámetros formales, por ahora no complicaremos las cosas. Veamos algunos ejemplos para afianzar todo lo dicho hasta ahora. program Raiz_n; { ------------------------------------------------------------Implementar una función que determine cualquier orden de raíz sobre cualquier base. ------------------------------------------------------------- } uses crt; var n : double; IndRaiz : double; { ------------------------------------------------------------ } function Raiz(N:double; IndRaiz:double):double; begin Raiz:=exp(ln(N)/IndRaiz); end; { ------------------------------------------------------------ } begin (* main *) clrscr; highvideo; n:=2; IndRaiz:=2; writeln('Raiz cuadrada de 2 = ',Raiz(2,2):2:8); readkey; end. Note la sencillez de esta función que está definida en una sola línea de códigos. Al tratarse de una sola línea es obvio que deberá contener el nombre de la función a fin de que ésta pueda retornar algún valor. Desde el punto de invocación (argumento de una instrucción writeln, la misma es llamada como cualquier otra función estándar propias de Pascal.
Observación importante. El hecho de poder implementar tantas funciones como se nos ocurra, y de que su invocación posee la sintaxis clásica de cualquier comando Pascal, implica que lo que en realidad estamos haciendo es crear nuevas instrucciones enriqueciendo las que ya traía el lenguaje de por sí. Esto le da al lenguaje una potencialidad asombrosa. He aquí más ejemplos:
Clase Teórica Nro 8
Pág. 4/11
INFORMATICA – C.B.I. (Ciclo Básico de Ingeniería) - 2015 Departamento de Ciencias de la Computación – FACET / UNT Grupo II – Dictado: Ing. Juan Manuel Conti. program ComplejoDeBinario_Exponencial; uses crt; var
Re,Im : double; Modulo : double; Fi : double;
{ ------------------------------------------------------------} function ModuloZ(Re:double; Im:double):double; begin ModuloZ:= sqrt(Re*Re+Im*Im); end; { ------------------------------------------------------------} function AnguloZ(Re:double; Im:double):double; const Kgrad = 180/PI; var Modu : double; Seno : double; begin Modu:= sqrt(Re*Re+Im*Im); if(Modu>0)then begin Seno:= Im/Modu; if(Seno>0)then if(Re=0)then Fi:=90 else if(Re