lunes, 1 de junio de 2009

UN EJEMPLO COMPLETO: EL PROGRAMA "calles.c"

A modo de glosario de lo visto hasta ahora vamos a desarrollar un programa que maneje muchos aspectos interesantes del lenguaje C, presentes en la mayoría de los programas que vayamos a realizar.

El programa 'calles.c' tiene como misión modificar el nombre de una calle (que se pasará como argumento de entrada) realizando sobre él una serie de abreviaturas (por ejemplo, cam-, biar 'teniente' por 'tte' o 'señor' por 'sr') y eliminando palabras no deseadas ('de', 'el', 'la',...). Se podría utilizar para minimizar el efecto de posibles duplicaciones en una base de datos que contuviese nombres de calles, con entradas como:

"SANTA CATALINA, PARQUE DE" "SAN ANDRES, CALLE"

El programa devolvería como salida los nombres:

"STA CATALINA PQE"

"S ANDRES CALLE"

donde ha reducido las palabras 'SANTA' y 'SAN' cambiándolas por 'STA' y 'S', y eliminado la partícula 'DE' y las comas de separación. Pensemos ahora en una gran base de datos, con 50.000 o más nombres de calles, que constituyan un índice, y el efecto de entradas como:

"SAN ANDRES, CALLE"

"S. ANDRES CALLE DE"

"DE SAN ANDRES, CALLE"

"SAN ANDRES CALLE"

Nuestro programa evitaría esta dispersión de nombres y los transformaría en el único nombre:

"S ANDRES CALLE"

facilitando su localización y eliminando la posibilidad de claves duplicadas por error.

El ejemplo no es muy importante en sí mismo, pero maneja conceptos aislados que sí son de interés; argumentos en la línea de llamada a un programa, manejo de arrays y estructuras con punteros, funciones propias y de la librería C estándar, y estructuras de control muy empleadas en C (for, if, if else, switch).

Para compilar el programa 'calles.c' habremos de utilizar el comando de sistema operativo:

ce -o calles calles.c y ejecutar el programa como:

calles 'SAN ANDRES, CALLE DE'

obteniendo como resultado:

Entrada: ->SAN ANDRES, CALLE DE <-Salida: ->S ANDRES CALLE<-

El listado del programa, casi sin ningún tipo de comentario para facilitar su seguimiento y el de su' estructura, es el que sigue (al final del capítulo se incluye con todos los comentarios"'autoex-plicativos).

Al principio del programa se declaran las variables globales calle[30] y palabra[30], como cadenas de caracteres, y se declara tabla como una función que devuelve un puntero a una cadena de caracteres.

Luego se define la estructura mapa, compuesta por carJn y car_out, punteros a las cadenas de caracteres de entrada y salida, respectivamente, calles se define como una estructura mapa, y se procede a inicializarla.

El número de elementos que contiene fe estructura calles se calcula como

short hi_calle=sizeof(calles) / sizeof(struct mapa);

Es decir, el número de elementos (hi_calle) equivale al tamaño (sizeof) de la estructura calles, dividido por el tamaño de un elemento (mapa).

En este caso main aparece como main(argc, argv), debida a que va a manejar argumentos en la línea de llamada (el nombre de la calle a modificar). El argumento se pasa entre comillas simples para evitar que los espacios en blanco intercalados hagan que sea considerado como varios argumentos.

Mediante un bucle for y el desplazamiento de un puntero arg[l], se va utilizando el argumento de entrada carácter a carácter. Si se encuentra un carácter distinto del separador (los separadores son '', V y ','), se carga en el array "palabra" y se incrementa el subíndice "i".

Si, por el contrario, se alcanza un separador entonces se añade un carácter nulo a «palabra», como terminador de cadena de caracteres, y se envía cornos-argumento a la funcióh-tabla, que nos devolverá un puntero a una 'cadena, bien apuntando a uña cadena distinta de la de entrada, si la encuentra en la estructura calles, o la misma cadena de entrada si no la ha encontrado. Al final le añade un espacio en blanco' como separador, y reinicializa el subíndice "i" a 0, para preparar la búsqueda de otra palabra.

Esta secuencia se repite hasta alcanzar el final de la cadena de entrada argv[l].

La función tabla tiene como misión efectuar la búsqueda de una palabra en la estructura calles, devolviendo la palabra modificada en caso de encontrarla. La búsqueda en la estructura se im-plementa mediante una búsqueda binaria.

Se compara la cadena a buscar con la correspondiente a la mitad de la tabla (que ha de estar ordenada), si es mayor la cárdena buscada se repite la búsqueda en la mitad superior de la tabla, si no en la inferior; y así sucesivamente hasta encontrar el elemento buscado o finalizar con una comparación entre dos posibles elementos. Si al final del proceso no se ha encontrado la cadena buscada, se devuelve un puntero a la misma cadena, para que el programa principal la añada a la cadena obtenida como resultado de salida.

Al final, se llama a la función trimar para que elimine los espacios en blanco que pudiera haber ál principio, final, y embebidos en la cadena obtenida como resultado del programa y se imprimen para su comparación las cadenas de entrada y salida.

La función trimar elimina los caracteres en blanco que pudiera haber en una cadena de caracteres, mediante el desplazamiento de un puntero. Cuando encuentra un blanco intermedio, pone a uno un indicador (dbl) y continúa la exploración de la cadena sin copiar ningún carácter a su salida. Cuando se encuentre un carácter distinto de blanco, si tiene a 1 el indicador dbl, entonces pone un blanco a su salida, y reinicializa dbl a 0. Luego copia sobre su salida el carácter distinto de blanco que acababa de encontrar. De este modo, ha convertido la aparición de múltiples blancos en uno solo. Al finalizar la exploración de la cadena, sitúa un carácter nulo como terminador de cadena de caracteres.

No hay comentarios:

Publicar un comentario