Objetivos Unidad 6 Realizar diseños modulares dividiendo el problema general en otros más sencillos utilizando para ello funciones y procedimientos en el lenguaje C++. Distinguir entre cómo se tratan en C++ los dos tipos de subprograma — procedimiento y función— y utilizar cada uno de ellos de forma adecuada. Establecer correctamente el paso de parámetros por valor y por referencia en C++. Diseñar programas que realicen múltiples llamadas a una función o procedimiento. Utilizar el diagrama jerárquico como herramienta para la comprensión de la estructura de un programa modular y tomarlo como base para la correcta escritura en C++. Usar adecuadamente variables locales y globales, evitando interferencias y efectos paralelos. n n n n Funciones en C++ n n n n n n n n Dado un programa escrito en C++ y realizado modularmente, saber determinar: q Si los parámetros son pasados por valor o referencia. q Si las variables son globales o locales a cada función o procedimiento. q Si las llamadas a subprogramas corresponden a función o procedimiento. q Cuáles son los parámetros reales y formales. q Los prototipos de funciones y procedimientos. Saber determinar los contenidos de las variables del programa principal y de las funciones y procedimientos durante la ejecución de un programa. Saber realizar algoritmos recursivos y seguir la traza correctamente. Utilizar correctamente el preprocesador de C y la construcción de macros. Saber realizar librerías de usuario en C++ y usarlas correctamente. Saber construir resguardos y conductores para la prueba y depuración de funciones y procedimientos que se incluirán en librerías de usuario. 1 Contenidos INTRODUCCIÓN FUNCIONES EN C++ n n q q q q q Vuelta de una función Tipos de valores devueltos por funciones de C++ FUNCIONES Y PROCEDIMIENTOS REGLAS DE ÁMBITO Y TIEMPO DE VIDA DE LAS FUNCIONES ARGUMENTOS DE LAS FUNCIONES n n n q q q Prototipos n q Paso por valor Paso por referencia Paso por dirección q q n q n Definiciones de macros: #define Inclusión de ficheros: directiva #include Compilación condicional Otras directivas n Modo_almacenamiento: q q n DISEÑO DE ARCHIVOS CABECERAS Y LIBRERÍAS DE USUARIO q n [Mod -Almac ] tipo_retorno Nombre_funcion (Lista_tipos_parametros ); Aparecerán antes de main () o en un fichero externo EL PREPROCESADOR q Prototipos de funciones Definición de funciones en C++ Llamada a una función SENTENCIA RETURN n 2 n n Resguardos y conductores Archivos de cabecera y librerías de usuario en C++ CONSTRUCCIÓN DE PROYECTOS CÓMO DOCUMENTAR UNA FUNCIÓN EJEMPLOS: int suma (int A, int B); // paso por valor y devolución de entero asociado a suma void intercambiar (int &, int &B); // sin valor asociado a intercambiar. Devuelve dos enteros modificados. RECURSIVIDAD n extern: accesibles desde cualquier fichero del programa. Por defecto. static : accesible por el fichero que contiene su declaración. Tipo_retorno : tipo dato asociado al nombre de función. Nombre_funcion. Lista_tipos_parametros: tipos de los parámetros formales, separados por coma. Si no hay void 3 Definiciones Llamadas de funciones [Mod-Almac]tipo_retorno Nombre_función (declaración-parámetros-formales) //Cabecera. { <declaración variables locales> //Cuerpo. <sentencias ó proposiciones> } Ejemplo: Nombre_funcion ([lista-parámetros-actuales]); n Ejemplos: ¿llamadas válidas? q q q floatdividir (intA, floatB) //cabecera { floatDIV; //Cuerpo if ( A = = 0) { printf(“ERROR NO SE PUEDE DIVIDIR POR 0. DEVUELVO UN 0 EN EL RESULTADO”); DIV = 0; } else DIV = B / A; return (DIV); } n 4 LA SENTENCIA return [(expresión)]; es obligatoria, salvo en el caso de tipo_retorno void q produce la asociación del nombre de la función con el valor q devuelto. 5 q q scanf (“%d%d”, &x, &y); Res = dividir (x, y); resultado=Potencia(base,expo); Potencia (base, expo)= resultado; Resultado = Auxiliar + potencia (2,3); if (potencia(bas,exp )==-1) //EJEMPLO COMPLETO #include<stdio.h> float multiplica (float, float); /* Prototipo de la función multiplica() */ main () { float a, b, total; printf ("\nTeclee dos números: "); scanf ("%f %f", &a, &b); total = multiplica (a, b); /* llamada a la fución*/ printf ("\nEl producto de ambos es %f", total); } float multiplica (float m, float n) /*definición de la función*/ { return (m * n); } 6 1 Argumentos de una función Función / Procedimiento FUNCIONES Prototipo: Llamada: Cabecera: PROCEDIMIENTOS tipo nombre (tipos_parámetros); void nombre ( tipos_pará metros); VAR = nombre (parámetros reales); nombre (parámetros reales); tipo nombre (decl_parám_formales) void nombre ( decl_parám_formales) return Sí. Prototipo: int max (int, int); Llamada: MAX=max (A,B); cabecera: int max(int a,int b ) { int c; if (a > b) c = a; Finalización: else c = b; return(c); } No. Prototipo: void error ( int); Llamda: error (z); Cabecera: void error (int x ) { switch (x) { case 1: printf(“Error valor incorrecto”) break; case 2: printf(“Error: opción no existente”) break; case 3: printf(“Error: dígito invalido” ) } }//Finalización POR VALOR: se produce una copia del valor POR REFERENCIA: Se trabaja con la misma zona de memoria ............ ............ void intercambiar (int,int); //prototipo void intercambiar (int&,int&); //prototipo,obsérvese el cambio ............. ............. void main (void ) { intNUM1, NUM2; printf (“\nEscriba dos números:”); scanf(“%d%d ”, &NUM1, &NUM2); if (NUM1>NUM2) { intercambiar (NUM1, NUM2); //llamada printf (“\nLos números intercambiados son: %d y %d.”,NUM1, NUM2); } } /***intercambia localmente el contenido de dosvariab entradas: dos números enteros precondiciones: ninguna salidas: no tiene postcondiciones:ninguna**********************/ void intercambiar (intpar_for1, intpar_for2) //cabecera { intaux; aux = par_for1; par_for1 = par_for2; par_for2 = aux ; } void main (void ) { intNUM1, NUM2; printf (“\nEscriba dos números:”); scanf(“%d%d ”, &NUM1, &NUM2); if (NUM1>NUM2) { intercambiar (NUM1, NUM2); //llamada printf (“\nLos números intercambiados son: %d y %d.”,NUM1, NUM2); } } /** intercambia el contenido de dos variables por referencia entradas/salidas: dos números enteros precondiciones: ninguna postcondiciones:Los números de la entrada quedan intercambiados**********************/ void intercambiar (int&par_for1, int&par_for2) //cabecera { intaux; aux = par_for1; par_for1 = par_for2; par_for2 = aux ; } 7 8 Recursividad Recursividad. Ejemplo • En programación una función es recursiva si puede llamarse a sí misma. • La recursividad es una alternativa a la iteración. • Normalmente las soluciones iterativas son más rápidas que las recursivas Solución iterativa de factorial: fact n= n*(n-1)*(n-2)*. . .*1 int factorial1(int NUM) { int SOLUCION=1,CONT; for (CONT=1 ;CONT <= NUM; CONT++) SOLUCION = SOLUCION * CONT; return (SOLUCION); } Llamada 1 n partes de un diseño recursivo: q q Programa principal caso general : es el caso Recursividad menor dentro de la indirecta definición de diseño Subprogram recursivo. a1 caso base: es el caso del que se conoce el valor, marca el fin del procedimiento recursivo. Subprogram a 1.1 n Recursividad directa Factorial2 es 6 NUM 3 Subprogram a2 Solución recursiva de factorial Caso general: n! = n (n-1)! Llamada 2 Caso base: 0! = 1 int factorial2 (int NUM) { int SOLUCION; if (NUM==0) Llamada 3 SOLUCION=1; else SOLUCION = NUM * factorial2 (NUM-1); return (SOLUCION); } Subprogram an Subprogram a 1.2 tipos de recursividad : q indirecta: subprograma A que llama a otro subprograma B que llama A. q directa: Cuando un subprograma se llama a sí mismo. Factorial2 es 2 NUM 2 Factorial2 es 1 NUM 1 Llamada 4 9 Preprocesador n Programa fuente .cpp q n preprocesador macros de función: q q #define Nombre_macro(arg1,..,argN ) Cadena_códigon en desuso, son auténticas funciones n anulación de macro: compilador n inclusión de ficheros: q Código objeto .obj q enlazador Programa ejecutable .exe #undef Nombre_macro #include <Nombrefichero> busca en los directorios definidos en la instalación de C q #include “Nombrefichero” busca en el directorio actual y después en los anteriores #include “c:\Borlandc\I n c\Prueba.h q #include Nombremacro la macro se expandirá en una de las formas anteriores, posible anidamiento ver pmacro.cpp #include <stdio.h> #define USA 0 #define GB 1 #if Ex_constante1 #define ESP 2 n compilación condicional II proposición1 #define PAIS ESP #ifdef [#elifnombre_macro Ex_constante2 #if PAIS == USA proposición char moneda[ ]= "dólar"; proposición2] #endif #elif PAIS == GB [#elif Ex_constante3 char moneda[ ]="libra"; #ifndef nombre_macro proposición3] #else proposición char moneda [ ]="euro"; [#elif E x_constanten #endif #endif proposición] void main (void) [#else { printf("\n PAIS = %d, moneda = %s", PAIS,moneda); proposición] } SALIDA:::::::::::PAIS = 2, moneda = euro #endif n #define Nombre_macro Cadena_código usadas hasta ahora Unidad de traducción 10 Otras directivas del preprocesador macros de objetos: q Factorial2 es 1 NUM 0 11 compilación condicional I #ifndef __STDIO_H //significa que no ha sido incluido stdio.h #include <stdio.h> #endif Ver otros ejemplos: páginas 263 -265 12 2 Librerías de usuario Pasos en el diseño de una librería Resguardo n Subprograma vacío con el mismo nombre e interfaz que la función o procedimiento que simula. n Conductor n Programa principal sencillo utilizado para depurar y probar funciones y procedimientos. n Ambos sirven para depurar programas y diseñar y probar funciones de librerías. n Ver ejemplo: pág 268 n n 13 Realizar programas conductores para implementar y depurar los módulos. Crear el archivo cabecera con: Inclusión de archivos. Definiciones de macros. Prototipos. Definiciones de funciones. Programa conductor para probar la librería. 14 Documentar funciones de librerías n n n n Cada función debe constar de: Sintaxis: archivo cabecera y prototipo. Descripción: Breve información sobre su uso, relaciones con otras funciones, entornos donde se puede usar. Ejemplo de uso. "Divide las dificultades que examines en tantas partes como sea posible, para su mejor solución". DESCARTES 15 16 3