Departamento de Computación Funciones UNAN - LEON Funciones •Una función es una colección independiente de declaraciones y sentencias, enfocadas a realizar una tarea específica. •Todo programa C consta al menos de una función, la función main, por donde empieza siempre la ejecución de un programa. void main( ) int fn1(int z) void fn2( ) { { { n = fn1(x); //........ m = fn1(y); fn2( ); } } //........ } Departamento de Computación 1 Funciones UNAN - LEON Pasar un array a una función • Cuando pasamos un array a una función lo que se escribe como argumento en la llamada a esa función es el nombre del array, es decir, el argumento que se pasa es la dirección del array, por lo que el parámetro formal correspondiente tiene que ser también un array, el cual, después de la llamada, queda inicializado con esa dirección. • Los arrays son siempre pasados por referencia, porque no se pasa una copia de todos sus elementos. Tanto la función que invoca, como la función invocada trabajan sobre el mismo espacio de memoria(sobre el mismo array). 2 1 Departamento de Computación Funciones UNAN - LEON • Cuando se declara un array unidimensional como parámetro de una función, no se requiere que se especifique su dimensión(no se hace una reserva de memoria para una copia total del array), ya que lo que se pasa es la dirección del array. int leer(tficha bibli[ ], int NMAX); • Si el array es multidimensional, no es necesario especificar la primera dimensión, pero sí las restantes. void CopiarArray(float destino[ ][COLS], float origen[ ][COLS]); • El nombre de pero en lugar podemos usar comienzo del mismo. un array y un puntero no son lo mismo, del nombre de una array unidimensional, un puntero que almacene la dirección de array para acceder a los elementos del 3 Departamento de Computación Funciones UNAN - LEON /********************** Programa Alumnos **********************/ // Versión con punteros #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #define N 100 /* número máximo de alumnos */ typedef struct { char matricula[10]; char apellidos[30]; char nombre[20]; char direccion[30]; } ficha; int leer(ficha *, const int); void buscar(ficha *, char *, int, int); int menu(void); 4 2 void main( ) { static ficha lista[N]; char dato[30]; /* dato a buscar */ int opcion; /* opción elegida en el menú */ int n = 0; /* número de alumnos leídos */ while (1) /* bucle infinito. Se sale con break. */ { opcion = menu( ); if (opcion != 4) { switch (opcion) { case 1: /* entrada de los datos de los alumnos */ n = leer(lista, N); break; case 2: /* búsqueda por el número de matrícula */ system("cls"); printf("Número de matrícula "); gets(dato); buscar(lista, dato, n, opcion); break; case 3: /* Búsqueda por los apellidos */ system("cls"); printf("Apellidos.......... "); gets(dato); buscar(lista, dato, n, opcion); break; } } else break; } } Funciones 5 Funciones /**************************************************************** Función para visualizar el menú ****************************************************************/ int menu(void) { int op; do { system("cls"); printf("\n\t1. Entrada de datos de alumnos\n"); printf("\n\t2. Búsqueda por nro. de matrícula\n"); printf("\n\t3. Búsqueda por apellidos\n"); printf("\n\t4. Fin\n"); printf("\n\nTeclee la opción deseada "); scanf("%d", &op); fflush(stdin); } while (op < 1 || op > 4); return (op); } 6 3 /**************************************************************** Función para leer los datos correspondientes a un alumno ****************************************************************/ int leer(ficha *lista, const int NMAX) { int n = 0; char resp = 's'; while (tolower(resp) == 's' && n < NMAX) { do { system("cls"); printf("Alumno número %d\n\n", n+1); printf("Número de matrícula "); gets(lista[n].matricula); printf("Apellidos.......... "); gets(lista[n].apellidos); printf("Nombre............. "); gets(lista[n].nombre); printf("Dirección.......... "); gets(lista[n].direccion); printf("\n\n¿ Datos correctos ? s/n "); resp = getchar(); fflush(stdin); } while (tolower(resp) != 's'); n++; printf("\n\n¿ Más datos a introducir ? s/n "); resp = getchar(); fflush(stdin); } return (n); } 7 Funciones /**************************************************************** Función para buscar si existe o no un dato ****************************************************************/ void buscar(ficha *lista, char *x, int alumnos, int opcion) { const int NO = 0; const int SI = 1; int existe = NO, i = 0; char resp; switch (opcion) { case 2: /* búsqueda por número de matrícula */ while (!existe && i < alumnos) if (strcmp(lista[i++].matricula, x) == 0) existe = SI; break; case 3: /* Búsqueda por apellidos */ while (!existe && i < alumnos) if (strcmp(lista[i++].apellidos, x) == 0) existe = SI; break; } 8 4 Funciones if (existe) printf("\n%s\n%s %s\n%s\n", lista[i-1].matricula, lista[i-1].apellidos, lista[i-1].nombre, lista[i-1].direccion); else printf("\n%s no existe", x); printf("\n\nPulse <Entrar> para continuar "); resp = getchar( ); fflush(stdin); } • El identificador de un array y un puntero no son lo mismo, lo que imposibilita en el caso de arrays de dos dimensiones utilizar en lugar del nombre del array, un puntero a un puntero que almacene la dirección de comienzo del array para acceder a los elementos del mismo. 9 Funciones /************** Fusionar dos listas clasificadas **************/ /* Versión con punteros */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define NML 120 /* número máximo de líneas */ #define CPL 60 /* caracteres por línea */ int fusionar(char **, int, char **, int, char **, const int); void Error(void); void main( ) { /* Inicializamos las listas a clasificar con el fin de no tener * que leer los datos y realizar así una prueba rápida. */ static char *listaActual[ ] = { "Ana", "Carmen", "David", "Francisco", "Javier", "Jesús", "José", "Josefina", "Luís", "María", "Patricia", "Sonia" }; 10 5 Funciones static char *listaNueva[ ] = { "Agustín", "Belén", "Daniel", "Fernando", "Manuel", "Pedro", "Rosa", "Susana" }; /* Calcular el número de elementos de los arrays anteriores */ const int dimA = sizeof(listaActual)/sizeof(listaActual[0]); const int dimN = sizeof(listaNueva)/sizeof(listaNueva[0]); /* Definir el array resultante de fusionar los anteriores */ static char **listaFinal; // referencia el array resultante int ind, r; /* Asignar memoria para el array de punteros listaFinal */ listaFinal = (char **)malloc((dimA+dimN) * sizeof(char *)); if (listaFinal = = NULL) Error( ); /* Inicializa el array de punteros. Esto evita problemas al liberar memoria, en el supuesto de un error por falta de memoria */ for (ind = 0; ind < dimA+dimN; ind++) listaFinal[ind] = NULL; /* Fusionar listaActual y listaNueva y almacenar en resultado en * listaFinal. La función "fusionar" devuelve un 0 si no se * pudo realizar la fusión. */ r = fusionar(listaActual, dimA, listaNueva, dimN, listaFinal, NML); Departamento de Computación 11 Funciones UNAN - LEON /* Escribir el array resultante */ if (r) { for (ind = 0; ind < dimA+dimN; ind++) printf("%s\n", listaFinal[ind]); } else Error( ); /* Liberar la memoria ocupada por el array listaFinal */ for (ind = 0; ind < dimA+dimN; ind++) free(listaFinal[ind]); free(listaFinal); } 12 6 Funciones /**************************************************************** FUSIONAR ****************************************************************/ int fusionar(char **listaA, int dimA, char **listaN, int dimN, char **listaF, const int nml) { int ind = 0, indA = 0, indN = 0, indF = 0; while (indA < dimA && indN < dimN) if (strcmp(listaA[indA], listaN[indN]) < 0) { listaF[indF] = (char *)malloc(strlen(listaA[indA]) + 1); if (listaF[indF] = = NULL) return 0; strcpy(listaF[indF++], listaA[indA++]); } else { listaF[indF] = (char *)malloc(strlen(listaN[indN]) + 1); if (listaF[indF] = = NULL) return 0; strcpy(listaF[indF++], listaN[indN++]); } 13 Funciones /* Los dos lazos siguientes son para prever el caso de que, * lógicamente una lista finalizará antes que la otra. */ for (ind = indA; ind < dimA; ind++) { listaF[indF] = (char *)malloc(strlen(listaA[indA]) + 1); if (listaF[indF] = = NULL) return 0; strcpy(listaF[indF++], listaA[ind]); } for (ind = indN; ind < dimN; ind++) { listaF[indF] = (char *)malloc(strlen(listaN[indN]) + 1); if (listaF[indF] = = NULL) return 0; strcpy(listaF[indF++], listaN[ind]); } return(1); } void Error(void) { puts("Longitud no válida de la lista resultante"); exit(1); } 14 7 Departamento de Computación Funciones UNAN - LEON Pasar una estructura a una función • Una estructura puede ser pasada a una función por valor o por referencia. • Cuando pasamos una estructura por valor, el parámetro actual que representa la estructura se copia en el correspondiente parámetro formal, produciéndose un duplicado. Si alguno de los miembros del parámetro formal se modifica, los cambios no afectan al parámetro actual correspondiente. • Si pasamos la estructura por referencia, lo que recibe la función es el lugar de la memoria donde se localiza dicha estructura. 15 /**************** Operaciones con complejos ****************/ #include <stdio.h> typedef struct { float real; float imag; } tcomplejo; void SumarComplejos(tcomplejo c1, tcomplejo c2, tcomplejo *p); void main( ) { tcomplejo ca, cb, cc; printf("\nIntroducir datos de la forma: x yi\n"); printf("ca = "); scanf("%f %f", &ca.real,&ca.imag); fflush(stdin); printf("cb = "); scanf("%f %f", &cb.real,&cb.imag); fflush(stdin); SumarComplejos(ca, cb, &cc); printf("Resultado: %g%+gi\n", cc.real, cc.imag); } void SumarComplejos(tcomplejo c1, tcomplejo c2, tcomplejo *p) { p->real = c1.real + c2.real; p->imag = c1.imag + c2.imag; } 16 8 Departamento de Computación Funciones UNAN - LEON Función que retorna un puntero • Cuando una función retorna un puntero a un objeto, el objeto debe persistir después de finalizar la función. /**************** Operaciones con complejos ****************/ #include <stdio.h> #include <stdlib.h> typedef struct { float real; float imag; } tcomplejo; tcomplejo *SumarComplejos(tcomplejo c1, tcomplejo c2); 17 void main( ) { tcomplejo ca, cb, *pcr; printf("\nIntroducir datos de la forma: x yi\n"); printf("ca = "); scanf("%f %f", &ca.real,&ca.imag); fflush(stdin); printf("cb = "); scanf("%f %f", &cb.real,&cb.imag); fflush(stdin); pcr = SumarComplejos(ca, cb); printf("Resultado: %g%+gi\n", pcr->real, pcr->imag); } tcomplejo *SumarComplejos(tcomplejo c1, tcomplejo c2) { tcomplejo cx; cx.real = c1.real + c2.real; cx.imag = c1.imag + c2.imag; return &cx; } 18 9 Departamento de Computación Funciones UNAN - LEON • El programa anterior presenta resultados inesperados. La función SumarComplejos, utiliza un complejo local cx del cual retorna su dirección. Cuando la función finalice el complejo cx se destruirá automáticamente, con lo que el puntero pcr que apunta al resultado, estará apuntando a un objeto inexistente. • La solución radica en hacer que la función SumarComplejos cree un objeto que persista a lo largo de la ejecución del programa, asignando memoria dinámicamente para el objeto. 19 /**************** Operaciones con complejos ****************/ #include <stdio.h> #include <stdlib.h> typedef struct { float real; float imag; } tcomplejo; tcomplejo *SumarComplejos(tcomplejo c1, tcomplejo c2); void main( ) { tcomplejo ca, cb, *pcr; printf("\nIntroducir datos de la forma: x yi\n"); printf("ca = "); scanf("%f %f", &ca.real,&ca.imag); fflush(stdin); printf("cb = "); scanf("%f %f", &cb.real,&cb.imag); fflush(stdin); pcr = SumarComplejos(ca, cb); printf("Resultado: %g%+gi\n", pcr->real, pcr->imag); /* Liberar la memoria asignada */ free(pcr); } 20 10 tcomplejo *SumarComplejos(tcomplejo c1, tcomplejo c2) { tcomplejo *pcx; /* Asignar memoria para el complejo suma */ pcx = (tcomplejo *)malloc(sizeof(tcomplejo)); if ( pcx = = NULL ) { printf("Memoria insuficiente\n"); exit(-1); } pcx->real = c1.real + c2.real; pcx->imag = c1.imag + c2.imag; return pcx; } 21 Departamento de Computación Funciones UNAN - LEON Funciones recursivas • Una función recursiva es aquella que se llama a sí misma. • El compilador C permite cualquier número de llamadas recursivas a una función. Cada vez que la función es llamada, los parámetros formales son inicializados. • Se utiliza una función recursiva, cuando el proceso a programar es por definición recursivo. Por ejemplo, el cálculo del factorial de un número por definición es un proceso recursivo. n! = n(n-1)! 22 11 /************* Cálculo del factorial de un número *************/ #include <stdio.h> unsigned long factorial(int n); void main( ) { int numero; unsigned long fac; do { printf("¿Número? "); scanf("%d", &numero); } while (numero < 0 || numero > 12); fac = factorial(numero); printf("\nEl factorial de %d es %ld\n", numero, fac); } unsigned long factorial(int n) { if (n = = 0) return 1; else return n*factorial(n-1); } 23 • Para n = 4, el proceso seguido por la función es: Nivel de recursión Proceso de ida Proceso de vuelta 0 1 2 3 4 factorial(4) 24 4 * factorial(3) 4*6 3 * factorial(2) 3*2 2 * factorial(1) 2*1 1 * factorial(0) 1*1 factorial(0) 1 • El uso de la recursión debe evitarse cuando haya una solución obvia por iteración. • La llamada a una función recursiva consume mucho espacio de pila debido a que por cada llamada las variables que intervienen en la función son salvadas en la pila para posteriormente poder iniciar la vuelta. 24 12 Departamento de Computación Funciones UNAN - LEON Funciones predefinidas en c • Funciones matemáticas: Las declaraciones para estas funciones están en el fichero math.h • Los argumentos y el resultado son de tipo double. • En muchos casos utilizaremos conversión cast para convertir explícitamente los argumentos al tipo deseado. Ejemplo: a = tan((double)valor); • Las funciones matemáticas se clasifican en: – – – – Funciones Funciones Funciones Funciones trigonométricas hiperbólicas. exponencial y logarítimica. varias. 25 Departamento de Computación Funciones UNAN - LEON • cos Resultado: el coseno de x ( x en radianes). #include <math.h> double cos(double x); • sin Resultado: seno de x ( x en radianes). #include <math.h> double sin(double x); • tan: Resultado: tangente de x ( x en radianes). #include <math.h> double tan(double x); 26 13 Departamento de Computación Funciones UNAN - LEON • exp Da como resultado el valor de ex ( e = 2.718282) #include <math.h> double exp(double x); • log Da como resultado el logaritmo natural de x . #include <math.h> double log(double x); • log10 Da como resultado el logaritmo en base 10 de x . #include <math.h> double log10(double x); 27 Departamento de Computación Funciones UNAN - LEON •ceil Resultado: un valor double, que representa el entero más pequeño que es mayor o igual que x. #include <math.h> double ceil(double x); double x = 2.8, y = -2.8; printf(“%g %g\n”,ceil(x),ceil(y)); •fabs Calcula el valor absoluto de x( siendo x un valor real en doble precisión). Las funciones abs y labs calculan el valor absoluto de un int y un long respectivamente. #include <math.h> double fabs(double x); 28 14 Departamento de Computación Funciones UNAN - LEON •floor Resultado: un valor double, que representa el entero más grande que es menor o igual que x. double floor(double x); double x = 2.8, y = -2.8; printf(“%g %g\n”,floor(x),floor(y)); •pow Resultado: xy. Si x es 0 e y es negativo o si x e y son 0 o si x es negativo e y no es entero, se obtiene un error(argumento fuera del dominio da la función). Si xy da un resultado superior al valor límite para el tipo double, el resultado es el valor límite(1.79769e+308) double pow(double x); double x = 2.8, y = -2.8; 29 printf(“%g\n”,pow(x,y)); Departamento de Computación Funciones UNAN - LEON •sqrt Calcula la raíz cuadrada de x. Si x es negativo, ocurre un error(argumento fuera del dominio de la función). #include <math.h> double sqrt(double x); Números seudoaleatorios •rand Da como resultado un número seudoaleatorio entero, entre 0 y el valor máximo para un int. #include <stdlib.h> int rand(void); 30 15 Departamento de Computación Funciones UNAN - LEON Funciones de fecha y hora •time Resultado: el número de segundos transcurridos desde las 0 horas del 1 de Enero de 1970. #include <time.h> time_t time(time_t *seg); •ctime Convierte un tiempo almacenado como un valor de tipo time_t, en una cadena de caracteres de la forma: Thu Jul 08 12:01:29 2010 #include <time.h> char *ctime(const time_t *seg); Devuelve un puntero a la cadena de caracteres resultante o un puntero nulo si seg representa un dato anterior al 131 de Enero de 1970. #include <stdio.h> #include <time.h> main( ) { time_t segundos; printf("El numero de segundos transcurridos desde el 01/01/1970 es %ld\n",time(&segundos)); printf("La fecha actual es %s",ctime(&segundos)); } • El tipo time_t está definido así: typedef long time_t; 32 16 Funciones para manipular bloques de memoria •memset Permite iniciar un bloque de memoria. #include <string.h> void *memset(void *destino, int b, size_t nbytes); destino: dirección del bloque de memoria que se desea inicializar. b: valor empleado para iniciar cada byte del bloque. nbytes: número de bytes del bloque que se iniciará. double a[10][10]; memset(a, 0, sizeof(a)); •memcpy Copia un bloque de memoria en otro. #include <string.h> void *memcpy(void *destino, const void *origen, size_t nbytes); 33 destino: es la dirección del bloque de memoria destino de los datos. origen: es la dirección del bloque de memoria origen de los datos. nbytes: número de bytes que se copiarán desde el origen al destino. double a[10][10], b[10][10]; memcpy(b, a, sizeof(a)); •memcmp Compara byte a byte dos bloques de memoria. #include <string.h> int memcmp(void *bm1, const void *bm2, size_t nbytes); bm1, bm2: son las direcciones de los bloques de memoria a comparar . nbytes: número de bytes que se compararán. double a[10][10], b[10][10]; if(memcmp(a, b, sizeof(a)) == 0) printf(“Las matrices contienen los mismos datos\n”); else printf(“Las matrices no contienen los mismos datos\n”); 34 17