Universidad de Costa Rica Facultad de Ingeniería Escuela de Ingeniería Eléctrica IE0117 – Programación bajo plataformas abiertas I ciclo 2012 Nota: 100 Excelente. Profesor Francisco Siles Canales Asistente Félix Suárez Bonilla Laboratorio Laboratorio 14 Estudiante Enrique Sáurez Apuy, A95872 Junio, 2012 1. Escriba una función que tome como argumento una cadena de caracteres, verifique que los caracteres de la cadena correspondan a un número de punto flotante válido y realice la conversión, retornando el valor resultante. Si la validación de la cadena falla, debe retornarse el valor -999999 (o cualquier otro valor que permita identificar una condición de error). Escriba además un pequeño programa que permita probar el funcionamiento de la función. La función debe ser capaz de identificar números de punto flotante escritos de distintas manejas (por ejemplo, 100, 42, 0.23, -.2345 y .20 son todos números de punto flotante válidos). Para realizar el programa solicitado en el enunciado primero lo que se hace es verificar si la primer posición es un signo, de ser negativo, se asigna a sign el valor de -1, de lo contrario se le asigna 1. Si se dio un signo al inicio, se aumenta el contador i, que muestra la posición del carácter del arreglo de caracteres que se está analizando. Luego se inicializa la variable val a cero, y se itera sobre el arreglo de caracteres mientras este sea un digito, y este se le suma a la variable val para que esta almacene su valor, multiplicando por 10 el valor anterior antes de sumarse. Cuando se sale de este ciclo significa o que se acabo el número o que es un punto, si es un punto, se suma 1 al contador i, para entrar al nuevo ciclo, que analizará si hay mas valores dígitos, de ser así se utiliza la variable power para almacenar el valor que se tiene que dividir para que la coma, quede en la posición correcta. Luego de la anterior iteración lo único que puede aparecer para que el número sea correcto es un \0 que es el carácter de finalización de número. De lo contrario significa que hay un error y se devuelve –9999999. El código ya compilado se muestra en prueba1.o #include <stdio.h> #include <string.h> #include <ctype.h> float conversion(char s[]){ //Se definen las variables float val, power; int i, sign; //Se asigna a i un cero i = 0; //Se verifica si la primer posiciÓn es -, de ser asÍ se asigna un -1 al signo sign = (s[i] == '-')?-1:1; //Si las primeras posiciones son - o + se suma uno a i, que es el que itera sobre el char if(s[i]=='+'||s[i]=='-'){ i++; } //Se recorre el char mientras s[i] sea un digito, y se le va asignando a val for(val = 0.0; isdigit(s[i]); i++){ val = 10.0 * val + (s[i]-'0'); } //Si se sale del ciclo anterior se verifica si la siguiente posicion es un punto, de ser asi, se le suma uno a i. if(s[i]=='.') i++; //Si luego del punto, hay mÁs números, se van sumando a la variable val, y se multiplica power por 10, que va a dar la posicion del decimal for(power = 1.0 ; isdigit(s[i]); i++){ val = 10.0 * val + (s[i]-'0'); power *= 10.0; } //Si luego de iterar sobre todas las condiciones anteriores no se llega al final de la palabra, significa que no era un número, por lo tanto se devuelve un -999999 if(s[i]!='\0'){ return -999999; } //Si no se entro en la condiciÓn anterior se devuelve el numero, que es el signo multiplicado por el numero y divido entre power. return sign * val / power; } //main con las pruebas int main(){ char s[1000] = "53.5868"; printf("El nÚmero es: %f \n",conversion(s)); char s1[1000] = "-23.8894"; printf("El nÚmero es: %f \n",conversion(s1)); char s2[1000] = "hola"; printf("El nÚmero es: %f \n",conversion(s2)); char s3[1000] = "+37372"; printf("El nÚmero es: %f \n",conversion(s3)); char s4[1000] = "-100"; printf("El número es: %f \n",conversion(s4)); char s5[1000] = "0.23"; printf("El número es: %f \n",conversion(s5)); char s6[1000] = "-.2345"; printf("El número es: %f \n",conversion(s6)); char s7[1000] = ".20"; printf("El número es: %f \n",conversion(s7)); return 0; } Código 1 Con las pruebas del main, se analizan las principales posibilidades para la conversión de string a flotante (se utilizaron todos los ejemplos del enunciado), los resultados se observan en la Figura 1. Donde los prints en la pantalla son los esperados, dado que se obtuvieron los números esperados. Figura 1; Prueba del código 1. 2. Escriba un programa que reciba, a través de la línea de comandos, el nombre de un archivo que contenga números enteros (uno por línea, máximo 100) en desorden, copie los números a un arreglo, ordene el arreglo de manera ascendente e imprima la lista de números ordenados en la terminal. Para realizar las acciones solicitadas primero es necesario abrir el archivo, lo cual se realiza utilizando fopen. Además es necesario reservar espacio de memoria para almacenar los números que trae el archivo, se reserva un tamaño igual a 100*sizeof(int), dado que en el enunciado se aclara que hay máximo 100 números. Posterior a esto se recorre el archivo, obteniendo cada línea, y almacenando el entero que hay en ella, en la posición que indica el contador i. De darse un EOF, se sale del for, y en caso de ser más de 100 líneas, el for no los toma en cuenta. En este caso se hace una conversión de string a integer. Posteriormente se imprime una línea, que indica que se ordenaron los números, y se utiliza la función interna de C, qsort para ordenar el arreglo de enteros, para esto fue necesario definir la función de comparación int_cmp que lo que hace es comparar a partir de los punteros si dos números cuales son mayores, iguales o menores. Por último se imprime la lista ya ordenada. (Solo se toman en cuenta las posiciones de memoria utilizadas), y se libera el espacio utilizado, y se cierra el archivo abierto. En el main solo se invoca a la función y se revisa la cantidad de parámetros enviados por el usuario, sea la correcta. El código ya compilado se llama prueba2.o #include <stdio.h> #include <stdlib.h> int int_cmp(const void *a, const void *b) { const int *ia = (const int *)a; //Se hace un casting para cambiar el tipo de puntero const int *ib = (const int *)b; return *ia - *ib; /*La comparación de enteros regresa un valor positivo si a es mayor que b, negativo si b es mayor que a, y 0 si son iguales*/ } void archivo(char *open){ /* Punteros a archivo */ FILE *origen; //Se definen las variables que se van a utilizar para iterar o guardar los valores de los caracteres. int i,j; int valor; char c; //Se define el puntero, que apunta a la primer posicion de memoria donde se van a guardar un vector con los enteros, a ordenar. int *p; //Se define que la posicion de memoria tiene 100 espacios, dado que este es el mayor tamaÑo estipulado en el enunciado p = (int *)malloc(100*sizeof(int) ); /* Abre los archivos */ origen = fopen(open, "r"); /* Comprueba que los archivos se hayan abierto correctamente */ if(origen == NULL) { fprintf(stderr, "Error de entrada/salida\n"); exit(2); } //Se itera sobre el archivo, sobre maximo 100 lineas. for(i=0;i<100;i++){ //En cada iteración se inicializar la variable valor en 0 valor = 0; //Mientras c sea distinto de EOF y fin de linea, captura el valor de c en valor, convirtiendolo en un int. while(((c = fgetc(origen)) != '\n')&&(c != EOF)){ valor = valor * 10 + (c-'0'); } //Se asigna al espacio de memoria p[i] el valor, de valor. p[i]=valor; //Si se dio fin de archivo, se da un break, dado que no hay mas nÚmeros if(c==EOF){ break; } } //Se imprime una instrucciÓn con lo que se va a hacer. printf("Los nÚmeros ordenados son:\n"); //Utilizando la funciÓn qsort implementada en la librerÍa de C, se ordena el arreglo de enteros. qsort(p, i, sizeof(int), int_cmp); //Luego de ordenarlos se imprime en la pantalla, utilizando un ciclo for for(j=0;j<i;j++){ printf("%d\n",p[j]); } /* Cierra el archivo */ fclose(origen); //Se libera la memoria utilizada free(p); } int main(int argc, char *argv[]) { /* Comprueba que la cantidad de argumentos sea la correcta */ if(argc != 2) { fprintf(stderr, "Error: Cantidad de argumentos incorrecta\n"); exit(1); } archivo(argv[1]); } Código 2 Para verificar el correcto funcionamiento del programa se generó el siguiente archivo con solo números (se acomodó en columnas en el presente documento, para facilitar su lectura): 3 2 1 8 11 3 7 8 9 1 2 3 4 5 6 7 8 9 1 5 3 3 5 2 1 2 3 4 5 6 7 8 9 7 8 6 4 234 4 6 78 8 5 7 9 7 6 5 4 3 3 5 6 7 8 9 4 5 3 3 3 34 45 6 8 7 5 4 7 8 9 3 4 5 44 3 45 6 7 9 45 6 5 4 3 2 2 6 8 89 9 23 45 7 8 9 6 235 Utilizando la siguiente línea en la terminal: ./prueba2.o hola.txt > a.txt Se almacena los resultados del programa en a.txt, los cuales se muestran a continuación Los números ordenados son: 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 11 23 34 44 45 45 45 45 78 89 234 235 De no colocarse el pipe a la llamada del programa, los números anteriores se mostrarían en la terminal, 1 por línea. Pero dada la cantidad de números una imagen de los mismo no aporta mayor valor al presente trabajo. Con lo cual se demuestra que el programa funciona correctamente, se puede generar cualquier archivo con números, y este los ordenará correctamente, con excepción a números con más de 100 líneas, donde solo tomará en cuenta las primeras 100 líneas, y procederá a ordenarlas. De aparecer letras, el programa los tomará como números, y calculará su correspondiente numérico – ‘0’, y los tratará como números y los ordenará como tal.