Procesamiento de la entrada del usuario

El procesamiento de la entrada del usuario, sobre todo por terminal, puede ser una de las labores más demandantes y tediosas de la programación, no obstante, es indispensable también.

La cantidad de errores que, intencional, maliciosa o accidentalmente pueden ocurrir es exageradamente amplia, por lo que un manejo robusto de todas las posibilidades es una labor extremadamente elaborada y necesariamente incompleta. Por ejemplo, ¿qué pasa sin el el scanf se le indica que se espera un número entero decimal (%d) y el usuario proporciona una letra o alguna otra cosa? El comportamiento, aunque indefinido en general, es que el programa parece enloquecer.

Como no hay forma de impedir que el usuario escriba cualquier barbaridad en el teclado, la solución usual es, leer la entrada como una cadena, y después analizar dicha cadena y extraer de ella la información que sea de nuestro interés. Esta es la razón principal por la que, en promedio, el 70% de las líneas de código de un programa suelen estar relacionadas con el procesamiento de la entrada del usuario y la salida, es decir, la forma en que se le presenta la información para que le resulte digerible.

fgets() 

La mejor forma estándar y segura de leer una cadena (línea de texto con o sin espacios) en el lenguaje C, es utilizando la función fgets. El ejemplo fgets.c muestra el uso de esta función.

Para leer una cadena, esta es la mejor opción ya que previene desbordamientos de búfer (buffer overflow), situación que no hacía gets (que está eliminada del estándar desde C23). fgets obliga al programador a especificar el tamaño máximo del búfer de almacenamiento, evitando que el programa escriba fuera de la memoria asignada.

Por otro lado, a diferencia de scanf("%s") que se detiene en el primer espacio en blanco, fgets captura la línea completa incluyendo espacios. Así mismo, contribuye al control de errores, ya que devuelve un apuntador (NULL) si ocurre un error o se llega al final del archivo (EOF).

Detalles a tener en cuenta:

• El salto de línea (\n): fgets almacena el carácter de nueva línea \n justo antes del \0. 
• Truncamiento: Si el usuario escribe más caracteres de los que caben en la cadena de almacenamiento, los caracteres sobrantes se quedan en el búfer de entrada (stdin) y podrían afectar a lecturas posteriores.

strcspn() 

¿Cómo eliminar el carácter de salto de línea (\n)? La forma más eficiente y moderna de eliminarlo es utilizando la función strcspn de la biblioteca string.h para buscar el \n y reemplazarlo por el terminador nulo \0. El ejemplo quita_enter.c muestra cómo hacerlo.

Ahora bien, ¿qué sucede si no se conoce con exactitud la longitud de una línea de entrada? Una posible solución es declarar un búfer o cadena lo suficientemente grande, pero puede darse el caso de que exista un desperdicio excesivo y prohibitivo de memoria, o que nuestro cálculo sea incorrecto y nos quedemos cortos. En cualquier caso, la solución no sólo es poco elegante sino inapropiada.

Lector de líneas dinámico (sin límite de búfer)

Si no se sabe qué tan larga será la línea del usuario y no se desea truncar el texto, es preciso hacer más trabajo: utilizar asignación dinámica de memoria.

En sistemas basados en POSIX (como Linux y macOS), existe la función estándar getline; sin embargo, una solución estándar que funcione igual en cualquier computadora con un compilador de C, requiere crear una función propia que utilice realloc y getchar como base. El ejemplo lectura_dinámica.c muestra la implementación de lo anterior dentro de la función leer_linea_dinamica.

Entrada de datos compuesta o compleja

Continuará...


 

 

No hay comentarios.:

Publicar un comentario