You are on page 1of 11

5

MODULARIDAD
Una vez conocidas las estructuras de control disponibles en la programacin estructurada, es posible desarrollar cualquier programa. Sin embargo, a medida que los problemas se hacen ms complejos, resulta ms difcil su resolucin como un todo, al tener que considerar simultneamente todos los aspectos que afectan al problema. En este captulo se introduce la modularidad, una tcnica basada en la separacin de problemas complejos en tareas ms simples, simplificando su resolucin y contribuyendo a mejorar la claridad de las soluciones alcanzadas. Adems, se estudiarn los mecanismos disponibles en C para implementar esta tcnica.

5.1 INTRODUCCIN A LA MODULARIDAD


La resolucin de un problema complejo puede simplificarse dividiendo a este en subproblemas ms sencillos y a estos, a su vez, en otros ms simples hasta que los ms pequeos sean fciles de resolver. Esta tcnica, basada en la estrategia divide y vencers, es empleada habitualmente en programacin y se conoce con el nombre de modularidad. A cada uno de los subproblemas considerados se le denomina mdulo. Para ilustrar esta idea, supngase que se desea desarrollar un programa para el clculo del IRPF. Acometer como un todo la resolucin de este problema, de considerable envergadura, sera una tarea complicada y el programa resultante contendra probablemente una gran cantidad de cdigo difcil de depurar y mantener. Sin embargo, este problema podra desglosarse en la solucin sucesiva de tareas ms simples, por ejemplo: lectura de los datos del contribuyente, clculo de los resultados y visualizacin de los resultados.

Clculo IRPF

Lectura datos

Clculo resultados

Visualizacin resultados

58

5. MODULARIDAD

Adems, la lectura de datos del contribuyente podra an desglosarse, por ejemplo, en lectura de datos personales y lectura de datos econmicos:

Clculo IRPF

Lectura datos

Clculo resultados

Visualizacin resultados

Datos personales

Datos econmicos

Las ventajas de esta forma de resolver los problemas son numerosas: Facilita la depuracin y el mantenimiento de programas. As, en el ejemplo del clculo del IRPF, un error en la lectura de la fecha de nacimiento del contribuyente podra buscarse directamente en el mdulo Datos personales, mientras que una modificacin de las escalas de gravamen afectara nicamente al mdulo Clculo resultados. Facilita el trabajo en equipo, ya que la asignacin de tareas puede hacerse de forma sencilla y, con una buena divisin modular, la independencia entre dichas tareas permitir a cada individuo concentrarse en su trabajo sin preocuparse del mtodo de resolucin empleado para realizar las restantes tareas. A este respecto, debe sealarse que el diseo modular ha de buscar siempre la encapsulacin de sus mdulos, es decir, la ocultacin de los aspectos internos de implementacin del mdulo (el cmo) al resto de mdulos que lo utilizan, los cuales slo requerirn conocer qu hace (el qu). Posibilita la reduccin del tamao de los programas, ya que un mdulo puede ser utilizado en varias ocasiones dentro de un mismo programa, mientras que las instrucciones que describen la tarea del mdulo slo ser necesario incluirlas una vez. Por ejemplo, en el clculo del IRPF la lectura y validacin de una fecha podra considerarse un mdulo independiente. Si durante la lectura de los datos personales es necesario leer la fecha del contribuyente y la de su cnyuge, slo ser necesario repetir la llamada a dicho mdulo y no la descripcin de cmo se realiza la lectura y validacin de una fecha. Favorece la reutilizacin del cdigo, es decir, el aprovechamiento de resoluciones de subproblemas llevadas a cabo con anterioridad. El desarrollo de mdulos que resuelven problemas frecuentes permitir al programador recopilar en una biblioteca de funciones propia una batera de soluciones genricas que incrementen su rendimiento futuro. Por ejemplo, un mdulo que lea una fecha y la valide podra reutilizarse fcilmente en la resolucin de otros problemas. Por lo tanto, la metodologa empleada consiste en comenzar, desde una visin general del problema, determinando los subproblemas que la componen. Cada uno de estos se divide a continuacin, si se estima necesario, en otros ms simples. Como se ha visto, esto puede representarse como una estructura jerrquica en cuya parte superior se encuentra el problema principal y en la inferior los subproblemas ms simples. Por esto, a esta metodologa tambin se la denomina de diseo descendente. Cada nivel de esta estructura representa un grado de detalle y, por tanto, de abstraccin, distinto.

59

5. MODULARIDAD

Las soluciones de un diseo descendente pueden implementarse en C con el concepto de mdulo. El mdulo correspondiente al problema principal se denomina programa principal y el resto de mdulos en los que se divide subprogramas. En lenguaje algortmico utilizaremos los trminos algoritmo principal y subalgoritmos. Normalmente, un mdulo es llamado desde otro mdulo situado en un nivel jerrquico superior al suyo. Tras la llamada, el flujo de ejecucin se traslada a la primera instruccin del mdulo llamado y comienza su ejecucin. Cuando esta termina, el control es devuelto al lugar del mdulo llamador desde el que el mdulo fue invocado. Como se ha comentado, esto puede ocurrir en diferentes lugares del mdulo llamador. A continuacin se ilustra esa transferencia del flujo de ejecucin en el ejemplo anterior.
Calculo IRPF
. . . leerDatos(...) . . calculoResultados(...) . . verResultados(...) . .
ada Llam

leerDatos(...)
. . . datosPersonales(...) . . . datosEconomicos(...) . . .
da ma Lla

datosPersonales(...)
. . . leerFecha(...) . . . . leerFecha(...) . . .
1 ada Llam 2 a ad m Lla

leerFecha(...)

Re to rn o 1 Re torn o2

Instrucciones del mdulo

o rn to Re

En C, el concepto de mdulo se corresponde con el de funcin. A continuacin, se detallan los aspectos de definicin y uso de las mismas.

5.2 DEFINICIN DE FUNCIONES


Matemticamente, una funcin es una operacin que toma uno o ms valores llamados argumentos o parmetros y genera un resultado basndose en estos. As, por ejemplo: f x , y = x 2 y 2 es una funcin cuyo nombre es f y cuyos parmetros son x e y. Obsrvese que en la definicin de la funcin no se asocia ningn valor especfico ni a x ni a y: diremos que x e y son los parmetros formales. Para evaluar la funcin y obtener un valor concreto es necesario asociar a los parmetros formales valores especficos que llamaremos parmetros reales. As, por ejemplo, los parmetros reales 3 y 4 para x e y, respectivamente, permiten obtener el valor 5 de la funcin f. En el Captulo 2 se presentaron algunas funciones que C lleva incorporadas, tales como funciones trigonomtricas, de redondeo, etc. Estas funciones se denominan funciones internas. Cuando el tipo de clculo deseado no lo cubren las funciones internas, es necesario recurrir a las funciones externas, que sern definidas por el programador mediante una definicin de funcin. La definicin de una funcin consiste en la descripcin del modo en que esta realiza su cometido. Al igual que en el caso de un programa sin modularidad, la definicin de una funcin se divide en tres fases: anlisis, diseo y resolucin en el ordenador. En la fase de anlisis, la especificacin de datos de entrada y datos de salida es semejante a la vista en captulos anteriores. Sin embargo, ahora, los datos de entrada podrn proceder tambin del mdulo llamador (en concreto, cuando se trate de los parmetros de la funcin). En ese caso, en la especificacin del dato de entrada se indicarn tambin las restricciones que se asume que ya 60

o rn to Re

5. MODULARIDAD

cumple dicho dato cuando llega a la funcin. Igualmente, los datos de salida pueden tener como destino, no solamente el monitor, sino tambin el mdulo llamador si son el resultado de la funcin. En la fase de diseo, en la parte declarativa y antes de la definicin de constantes simblicas y la declaracin de variables de que haga uso la funcin, deber indicarse la cabecera de la funcin, que contendr los identificadores de los parmetros formales, el tipo asociado a cada uno de ellos y el tipo asociado al valor devuelto por la funcin, utilizando el siguiente diagrama sintctico:
identificador del mdulo ( identificador de parmetro , : tipo ) : tipo

El identificador del mdulo se refiere al nombre de la funcin. A continuacin, entre parntesis, se incluirn los identificadores de los parmetros formales junto con sus tipos correspondientes (o nicamente los parntesis si la funcin carece de parmetros). Por ltimo, se indicar el tipo devuelto por la funcin. La representacin algortmica ser muy similar a la vista en el Captulo 3 para un algoritmo completo. La nica diferencia es que en un subalgoritmo, el primer smbolo del que parten el resto de instrucciones ser el que se indica a continuacin: identificador_mdulo(lista de parmetros) BLOCK La lista de parmetros se refiere a los parmetros formales que utiliza la funcin. Ser, por lo tanto, una lista de identificadores separados por comas (sin indicar tipos). En cuanto a identificador_mdulo ser el nombre de la funcin. Adems, para expresar en el subalgoritmo el valor que finalmente devolver la funcin como resultado al mdulo llamador, se emplear la siguiente representacin: devolver(expresin) En la fase de resolucin en el ordenador, en C la definicin de una funcin se sita despus del programa principal (funcin main()). Una funcin tiene una constitucin similar al programa principal, es decir, posee una seccin de definicin de constantes simblicas, una cabecera de funcin y un cuerpo que contiene la declaracin de variables y las instrucciones correspondientes al diagrama de Tabourier. La cabecera, sigue el siguiente diagrama sintctico:
tipo identificador de la funcin ( tipo identificador de parmetro , )

Las secciones de definicin de constantes simblicas y declaracin de variables contendrn, respectivamente, las constantes simblicas y variables que la funcin utilice. El resto del cuerpo estar formado por el conjunto de instrucciones que llevan a la obtencin del valor que la funcin debe devolver. La ltima instruccin del cuerpo de la funcin deber ser de la forma: return expresin; indicando as el valor que esta devuelve como resultado al mdulo llamador.

61

5. MODULARIDAD

EJEMPLO 5.1. Desarrollar un mdulo que calcule y devuelva el factorial de un nmero recibido como parmetro. ANLISIS: a) Datos de entrada: n: Valor del que quiere calcularse el factorial. Mdulo llamador. (n 0) b) Datos de salida: factorial: Factorial de n. Mdulo llamador. c) Comentarios: Emplearemos una variable para contar el nmero de multiplicaciones efectuadas. DISEO: a) Parte declarativa: factorial(n:entero):real VARIABLES i:entero f:real b) Representacin algortmica: factorial(n) BLOCK f1
i 2, n, 1

M. llamador f n

factorial

for do

devolver (f) f fi

CODIFICACIN:
/* factorial(n) */ /* Devuelve el factorial de un nmero n */ double factorial(int n) { int i; double f; f=1; for (i=2; i<=n; i=i+1) f=f*i; return f; }

5.3 INVOCACIN DE FUNCIONES


Para emplear una funcin es necesario invocarla desde otro mdulo. Dado que la invocacin se sustituir por el resultado devuelto, esta deber formar parte de una expresin para que su valor no se pierda en el mdulo llamador. La sintaxis que se utiliza es la siguiente: ...identificador_funcin(lista de parmetros reales)... La lista de parmetros se refiere a los parmetros reales y ser una lista de expresiones separadas por comas. El nmero de parmetros reales incluidos en esta lista debe coincidir con el de parmetros formales indicados en la cabecera de la funcin durante su definicin. Adems, el tipo de cada parmetro real debe coincidir con el de su correspondiente parmetro formal o, en caso contrario, se producir una conversin de tipo que puede provocar prdida de informacin.

62

5. MODULARIDAD

Una llamada a una funcin implica los siguientes pasos: 1. El control de la ejecucin se transfiere del mdulo llamador a la funcin. 2. A cada parmetro formal se le asigna el valor del parmetro real que ocupe su misma posicin en la lista de parmetros. 3. Se ejecutan las instrucciones de la funcin. 4. El valor de la funcin es devuelto al mdulo llamador junto con el control de la ejecucin. 5. Se evala la expresin del mdulo llamador que contiene a la invocacin. El uso de mdulos definidos por el programador tambin afecta a las distintas fases de resolucin del mdulo llamador. En la fase de anlisis, deber incluirse un comentario por cada uno de los mdulos definidos por el programador que vayan a utilizarse, indicando su cometido y una descripcin de la informacin que se transferir desde y hacia el mdulo llamador. En la fase de diseo, en la parte declarativa y tras la definicin de constantes simblicas, deber indicarse la lista de mdulos a los que se invoca, empleando para cada uno la siguiente sintaxis:
identificador del mdulo ( tipo , ) : tipo

y precediendo a toda la lista del epgrafe MDULOS LLAMADOS. En la representacin algortmica, los pasos que contengan una invocacin a un mdulo definido por el programador estarn encerrados en el siguiente smbolo:

Por ltimo, en la fase de resolucin en el ordenador, en C deber indicarse, inmediatamente despus de la seccin de archivos de cabecera y de definicin de constantes simblicas del programa principal, para cada funcin externa utilizada en el programa, un prototipo de funcin, que debe seguir el siguiente diagrama sintctico:
tipo identificador de la funcin ( tipo , EJEMPLO 5.2. Calcular y mostrar por pantalla el nmero de combinaciones sin repeticin de n elementos tomados de m en m, solicitando n y m por teclado. ANLISIS: a) Datos de entrada: n: nmero total de elementos. Teclado. (n > 0) m: tamao de cada grupo de elementos tomado. Teclado. (n m > 0) M. P. n n f factorial ) ;

leerPositivo b) Datos de salida: result: nmero de combinaciones sin repeticin de n elementos tomados de m en m. Monitor. c) Comentarios: Se utilizar un mdulo para leer un nmero positivo desde teclado. Devolver dicho nmero.

63

5. MODULARIDAD

Se utilizar un mdulo para calcular el factorial de un nmero. Recibir dicho nmero y devolver el factorial calculado. DISEO: a) Parte declarativa: MDULOS LLAMADOS leerPositivo():entero factorial(entero):real VARIABLES n,m:entero result:real b) Representacin algortmica: combinatorio BLOCK nleerPositivo() mleerPositivo() m>n escribir ("Error") CODIFICACIN:
/***********************************/ /*** C O M B I N A T O R I O ***/ /***********************************/ #include <stdio.h> /* Prototipos de funciones */ int leerPositivo(); double factorial(int); /* Programa principal */ int main() { int n,m; double result; printf("Introduce un nmero: "); n=leerPositivo(); printf("Introduce otro nmero: "); m=leerPositivo(); while (m > n) { printf("Error, el segundo valor debe ser menor que %d: ",n); m=leerPositivo(); } result=factorial(n)/(factorial(m)*factorial(n-m)); printf("Combinaciones de %d elementos tomados de %d en %d (s.r.)= %.0f", n,m,m,result); return 0;

while do BLOCK

resultfactorial(n) / (factorial(m)factorial(n-m))

escribir (result)

mleerPositivo()

/* leerPositivo */ /* Devuelve un nmero positivo ledo desde teclado */ int leerPositivo() ... (aqu se situar la definicin de la funcin leerPositivo) /* factorial(n) */ /* Devuelve el factorial de un nmero n */ ... (aqu se situar la definicin de la funcin leerPositivo)

64

5. MODULARIDAD

5.4 MDULOS QUE NO DEVUELVEN NINGN VALOR


Como se indicaba en la introduccin, el objetivo de la modularidad es dividir un problema en subproblemas ms simples. Por ello, a veces puede convenir separar en un mdulo un conjunto de instrucciones que representen una subtarea independiente dentro del programa, incluso aunque dicho mdulo no proporcione ningn resultado al mdulo llamador. Tal es el caso, por ejemplo, de un mdulo que muestre por pantalla las instrucciones de uso de un programa. En la fase de diseo, la definicin de un mdulo que no devuelve ningn valor al mdulo llamador se indicar omitiendo la parte :tipo del final de la cabecera del mdulo. Adems, en el diagrama de Tabourier, no se incluir al final la operacin devolver que se estudi en la seccin anterior. En la fase de resolucin en el ordenador, la cabecera de la funcin comenzar situando la palabra clave void en el lugar del tipo devuelto por la funcin y se omitir la instruccin return al final del cuerpo de la funcin. La invocacin de un mdulo que no devuelve ningn valor se efectuar de forma idntica a como se hace con otra funcin, es decir, identificador_funcin(lista de parmetros) teniendo en cuenta que ahora debe aparecer independientemente y no como parte de una expresin, ya que no hay un resultado asociado a la invocacin.
EJEMPLO 5.3. Desarrollar un mdulo que muestre por pantalla la tabla de multiplicar de un nmero entero indicado como parmetro. ANLISIS: a) Datos de entrada: mult: valor del que se mostrar la tabla de multiplicar. Mdulo llamador. b) Datos de salida: tabla[10]: Valores de la tabla de multiplicar de mult. Monitor M. llamador mult

tablaMultiplicar c) Comentarios: Utilizaremos una variable para contabilizar el nmero de multiplicaciones mostradas durante la visualizacin de la tabla de multiplicar. DISEO: a) Parte declarativa: tablaMultiplicar(mult:entero) VARIABLES i:entero b) Representacin algortmica: tablaMultiplicar(mult) BLOCK escribir (Tabla,mult) i 1, 10, 1 for do escribir (i,mult,imult)

65

5. MODULARIDAD

CODIFICACIN:
/* tablaMultiplicar(mult) */ /* Calcula y muestra la tabla de multiplicar de 'mult' */ void tablaMultiplicar(int mult) { int i; printf(" TABLA DE MULTIPLICAR DEL %2d\n",mult); printf("=============================\n"); for (i=1; i<=10; i=i+1) printf("%10d X %2d = %2d\n",i,mult,i*mult); }

5.5 MDULOS QUE DEVUELVEN MS DE UN VALOR


Las funciones devuelven, como mximo, un resultado asociado al nombre de la funcin. En los ejemplos anteriores, los parmetros se han utilizado para enviar valores desde el mdulo llamador al mdulo llamado. Este modo de transferir informacin entre mdulos mediante parmetros se denomina pase de parmetros por valor y consiste en copiar el valor del parmetro real en el correspondiente parmetro formal (los parmetros real y formal representan direcciones de memoria distintas). Por lo tanto, el pase de un parmetro por valor constituye un canal de comunicacin unidireccional desde el mdulo llamador hacia el mdulo llamado. A travs de ellos solo puede enviarse informacin desde el mdulo llamador hacia el mdulo llamado ya que las modificaciones que pudieran producirse en los parmetros formales dentro del mdulo llamado no quedan reflejadas en los parmetros reales especificados en la invocacin. As, aunque la funcin factorial del Ejemplo 5.1 se hubiera definido de forma que el parmetro formal n modificara su valor dentro de la funcin:
double factorial(int n) { double f; if (n < 2) f=1; else { f=n; while (n > 2) { n=n-1; f=f*n; } } return f; }

el resultado del clculo combinatorio del Ejemplo 5.2 seguira siendo correcto, ya que las modificaciones que sufre el parmetro formal n dentro de la funcin no afectan al parmetro real con el que se realiza cada llamada. Cuando necesitemos definir un mdulo que devuelva ms de un valor al mdulo llamador, deberemos utilizar otro modo de transferir informacin entre mdulos: el pase de parmetros por referencia. Este modo permite establecer un canal de comunicacin bidireccional entre el mdulo llamador y el mdulo llamado. En concreto, consistir en transferir al mdulo llamado la direccin del parmetro real (utilizando el operador de direccin, &), en lugar de transferir una copia de su 66

5. MODULARIDAD

valor (parmetros real y formal representarn la misma direccin de memoria). As, a diferencia de lo que ocurre con el pase de parmetros por valor, las modificaciones realizadas sobre un parmetro formal pasado por referencia tambin se efectan sobre su correspondiente parmetro real, quedando as reflejadas en el mdulo llamador. Un mdulo puede pasar por referencia tantos parmetros como se quiera, ampliando as el nmero de valores que el mdulo puede devolver al mdulo llamador.1 Obsrvese que un parmetro pasado por referencia siempre actuar, al menos, como dato de salida del mdulo (a veces, podr actuar tambin como dato de entrada). En el caso de que el dato fuera slo de entrada al mdulo, el parmetro deber pasarse por valor.
EJEMPLO 5.4. Desarrollar un mdulo que intercambie en el mdulo llamador el valor de dos variables enteras. ANLISIS: a) Datos de entrada: x: valor a intercambiar. Mdulo llamador. y: valor a intercambiar. Mdulo llamador. b) Datos de salida: x': valor intercambiado (la y original). Mdulo llamador. y': valor intercambiado (la x original). Mdulo llamador.

M. llamador x,y intercambio

c) Comentarios: Ser necesario utilizar una variable auxiliar que mantenga uno de los valores iniciales temporalmente, con el objetivo de que este no se pierda tras la primera asignacin. DISEO: a) Parte declarativa: intercambio(*x:entero, *y:entero) VARIABLES aux:entero b) Representacin algortmica: intercambio(x,y) BLOCK auxx CODIFICACIN:
/* intercambio(x,y) /* Intercambia los valores de x e y void intercambio(int *x, int *y) { int aux; aux=*x; *x=*y; *y=aux; */ */

xy

yaux

1 Si bien el lenguaje C permite que un mismo mdulo devuelva simultneamente un valor asociado al nombre de la funcin y otros valores asociados a parmetros pasados por referencia, el uso simultneo de ambos mtodos no se considera una buena prctica de programacin. Por ello, emplearemos el primer mtodo cuando el mdulo devuelva un nico valor y el segundo cuando devuelva ms de uno.

67

5. MODULARIDAD

5.6 ARRAYS COMO PARMETROS


Como se estudi en el tema anterior, en lenguaje C, el identificador de un array es un puntero al primer elemento del array. Por ello, al pasar un array a un mdulo como parmetro, realmente estaremos pasando la direccin del array y no su contenido. En otras palabras, cuando se trate de arrays, el pase de parmetros se hace siempre por referencia. Por lo tanto, habr que prestar especial cuidado cuando se trabaje dentro de un mdulo con parmetros de tipo array, pues las modificaciones que se hagan en el parmetro formal siempre se reflejarn en el correspondiente parmetro real del mdulo llamador. En la declaracin de parmetros formales de tipo array se indicar, entre corchetes, la longitud de cada dimensin, excepto la primera, que podr omitirse (aunque no los corchetes). Por ejemplo, si queremos definir un mdulo que lea desde teclado una matriz de enteros de 105 y la devuelva al mdulo llamador, un posible prototipo de funcin sera: En algoritmia:
leerMatriz([][5]:entero)

En C:
void leerMatriz(int [][5]);

mientras que en la cabecera de la funcin sera: En algoritmia:


leerMatriz(m[][5]:entero)

En C:
void leerMatriz(int m[][5])

68

You might also like