Fundamentos de programación Programas y Subprogramación Subprogramación Estructura de un programa en C • Directivas del preprocesador • Declaraciones globales y/o externas - Prototipos de funciones (cabeceras) - Variables • Declaraciones de funciones (subprogramación) - Función principal main - Definición, en su caso, de otras funciones Subprogramación ¾ La subprogramación permite dividir un programa en partes más pequeñas, cada una de ellas con un propósito único e identificable. De esta forma, un programa en C se construye modularmente usando funciones. ¾ La ejecución del programa siempre empieza por la función principal main. Si un programa C tiene varias funciones, sus definiciones pueden aparecer en cualquier orden, pero deben ser independientes unas de otras. Funciones Una función en C • Debe tener un nombre (identificador). • Es conveniente que realice una tarea concreta. • Puede cambiar datos (parámetros). • Puede retornar un valor. Dato 1 ··· ··· ··· Dato N Resultado Funciones <tipo> <nombre> (<tipo1> par1,...,<tipoN> parN) { <cuerpo de la función> } <tipo> : Tipo de datos de retorno de la función, por defecto int <nombre> : Identificador para efectuar llamadas a la función. <tipoX> parX : Tipo y nombre de los parámetros formales. <cuerpo de la función> : Declaración de variables locales, sentencias de control, llamada a otras funciones, … Puede incluir la sentencia return. Funciones #include <stdio.h> long int fact ( int x ); /* prototipo de la función */ void main() { int num, veces = 10; while(veces--) { scanf(“%d ”, &num); printf(“factorial de %d = %ld\n”, num, fact(num) ); } } long int fact (int x) { int i; long int f = 1; for (i = 2; i <= x; i++) f = f * i; return f; } Funciones Visibilidad de variables: auto static extern register Variables locales • Ambito: interior de la función. • Tiempo de vida: ejecución de la función (excepto static). Variables globales • Ambito: todas las variables del fichero (efectos colaterales). • Tiempo de vida: ejecución del programa. Funciones Proceso de una función C • Los parámetros reales (llamada o activación) se asocian con los parámetros formales (definición). • Se reserva memoria para parámetros y su inicialización. • Se reserva memoria para variables locales. • Ejecución de las sentencias. • Anotación del resultado (si lo hay). • Liberación de memoria local. • Vuelta al punto de llamada y uso del resultado (si lo hay). Funciones Los parámetros en C son por valor #include <stdio.h> void cubo ( int x ) { x = x * x * x; printf(“Dentro de la función } x = %d\n”, x); void main() { int x = 5; printf(“Antes de la llamada x = %d\n”, x); cubo( x ); printf(“Después de la llamada x = %d\n”, x); } Ejecución Antes de la llamada x = 5 Dentro de la función x = 125 Después de la llamada x = 5 no cambia Funciones Los parámetros en las funciones C son siempre por valor. Para cambiar un determinado parámetro, C proporciona un mecanismo de acceso a direcciones de memoria. • Operador de dirección ( & ) Obtiene la dirección en memoria de una variable. • Operador de indirección o puntero ( * ) Obtiene el dato contenido en una dirección de memoria. Funciones #include <stdio.h> void intercambiar (int * x, int * y) { int aux; aux = *x; *x = *y; *y = aux; } void main() { int a,b; scanf(“%d %d”, &a, &b); /* a = 10, b=20 */ printf(“Valores a = %d y b = %d\n”, a, b); intercambiar( &a, &b ); printf(“y ahora son a = %d y b = %d\n”, a, b); } Funciones Paso de parámetros por valor • Declaración <tipo> <nombre_función> (<tipo1> par1, <tipo2> par2,... ) • Llamada nombre_función (expresión1,expresión2,... ); Paso de parámetros por referencia • Declaración <tipo> <nombre_función> (<tipo1> *par1, <tipo2> *par2,... ) • Llamada nombre_función ( &variable1,&variable2,... ); Funciones Pasar de coordenadas rectangulares a polares #include <math.h> ··· ··· ··· void rect2polar (double x, double y, double *r, double *t) { *r = sqrt(x * x + y * y); *t = atan(y/x); } ··· ··· ··· rect2polar(4,3,&radio,&angulo); Introducción a la recursividad Una función es recursiva si dentro de su cuerpo se produce al menos una llamada a sí misma. Consideremos la sucesión de Fibonacci: a0, a1, a2, a3, a4, a5, a6, … = 1, 1, 2, 3, 5, 8, 13, … Los dos primeros elementos de la sucesión son 1 y el resto se obtiene sumando los dos términos inmediatamente anteriores. Introducción a la recursividad Sucesión de Fibonacci: versión iterativa long int fibiter (int n) /* n >= 0 */ { long int prim = 1, seg = 1; while (n > 1) { seg = prim + seg; prim = seg - prim; --n; } return seg; } Introducción a la recursividad Sucesión de Fibonacci: versión recursiva a0 = a1 = 1 an = an-1 + an-2 para n > 1 long int fibrec (int n) /* n >= 0 */ { if (n == 0 || n == 1) return 1; else return fibrec(n - 1) + fibrec(n - 2); } Introducción a la recursividad Toda función recursiva debe constar de – Un caso base, en el que se especifica el valor de la función para uno o varios valores. – Un paso recursivo (o más), donde el resultado de la función se define en términos de valores que ya han sido calculados previamente. Introducción a la recursividad n! factorial de un entero positivo n Producto de los n primeros números naturales. 0! = 1, n! = n * (n – 1) * (n – 2) * ··· * 3 * 2 * 1 long int fact (int n) { long int f = 1; for( ; n > 1; n--) f *= n; return f; } Introducción a la recursividad Versión recursiva de n ! 0! = 1 n! = n * (n – 1)! para n > 0 long int fact (int n) { if (n == 0) return 1; else return n * fact(n - 1); } Introducción a la recursividad Ejecución de fact(3) fact(3) 3 * fact(2) 2 * fact(1) 1 * fact(0) 1 1 2 6 Introducción a la recursividad #include <stdio.h> void EscribirNum (int n); void main () { EscribirNum(3); } Salida: 3210 void EscribirNum (int n) { printf(“%d”,n); if (n > 0) EscribirNum(n - 1); } Introducción a la recursividad Ejecución de EscribirNum(3) EscribirNum (3) 3 EscribirNum(2) 2 EscribirNum(1) Salida: 3210 1 EscribirNum(0) 0 Introducción a la recursividad #include <stdio.h> void Escribir2Num (int n); void main () { Escribir2Num(3); } Salida: 0123 void Escribir2Num (int n) { if (n > 0) Escribir2Num(n - 1); printf(“%d”,n); } Introducción a la recursividad Ejecución de Escribir2Num(3) Escribir2Num(3) Salida: 0123 Escribir2Num(2) Escribir2Num(1) Escribir2Num(0) 3 2 1 0 Introducción a la recursividad void main(void) { int a,b; do scanf(“%d %d”,&a,&b); while (a <= 0 || b <= 0); printf(“El mcd de %d y %d es: ”,a,b); while (a != b) { while (a > b) a -= b; while (b > a) b -= a; } printf(“%d”,a); } Introducción a la recursividad void main(void) { int a,b; do scanf(“%d %d”,&a,&b); while (a <= 0 || b <= 0); printf(“El mcd de %d y %d es: %d\n”, a, b, mcd(a,b) ); } int mcd (int a, int b) { /* Escribir el cuerpo de la función recursiva equivalente */ }