Leyendo de la entrada estándar con scanf y fgets

Hace tiempo, les contaba que me inicié en la programación competitiva, en la cual, la mayoría de problemas nos piden leer información de la entrada estándar o stdin seguramente me lo van a creer... yo no sabía cómo hacerlo de una manera "correcta" (._. ), en especial cuando de cadenas se trataba. En este post trataré de explicar cómo es que lo hago (y he aprendido que lo hacen) en C o C++.

La función scanf

Esta función mágica llega a nosotros gracias a la librería <stdio.h> en C o <cstdio> en C++, resulta la manera básica de recuperar valores. Nos sirve para todo tipo de entradas y si no tienes algo muy complicado de leer, esta es tu mejor opción, recuerda que esta función trata de leer el tipo de dato que le especifiques hasta que encuentra un salto de línea o un espacio en blanco. El uso de esta función depende de los especificadores de formato para recuperar los valores que deseas.

Por ejemplo, supongamos que tenemos la siguiente entrada
10 3161565164181
aab baa aba
y este código para leerlo
int a;
long long int b;
char cadena[15];
scanf("%d %lld", &a, &b); 
scanf("%s", cadena); // 'cadena' es ya una referencia a memoria
Una vez que se ejecute, en a tendremos 10, en b tendremos 3161565164181 y cadena será "aab" (¡porque solo lee hasta el espacio en blanco!).

La función fgets

Pero, qué pasa si la entrada es un poco más complicada, como la del problema Wetlands of Florida en la que vienen secuencias de caracteres seguidas inmediatamente por un par de números enteros:
// ...
LLLLLLLLL
3 2
// ...
Para ello se ocupa la función fgets (que es parecida a gets, solo que más segura), en combinación con sscanf que funciona de manera similar a scanf solo que esta "lee" de una secuencia de caracteres y no de stdin. En cuanto a fgets, sus parámetros son: la dirección de memoria, la cantidad de caracteres que esperamos leer como máximo, y el flujo del que los vamos a extraer, de tal manera que tenemos algo así:
int i, j;
char entrada[10];
fgets(entrada,10,stdin);
// Procesamos 'entrada', que contiene la siguiente secuencia de caracteres: 
// 'L','W','W','W', 'L', 'L', 'L', 'L', 'W' y '\n' <= ¡Sí! el salto de línea
// Recuperamos los enteros:
fgets(entrada,10,stdin);
sscanf(entrada,"%d %d",&i,&j);
Ya para finalizar es necesario remarcar esto: fgets recupera hasta que encuentra el salto de línea. Repito: fgets recupera hasta que encuentra el salto de línea por lo que es necesario eliminarlo "a manita" con '\0' si es que no es lo que deseamos de él. 
Espero que les sirva como a mi me ha servido, ya que hay que recordar que una parte importante de resolver los problemas es saber interpretar de manera adecuada la entrada que nos dan, así como saber introducirla dentro de nuestra probable solución a este.


¡Saludos!
@fferegrino :)

4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Oie bien explicado, nunca había utlizado: long long int b; y después recibirlo con %lld

    ReplyDelete
    Replies
    1. Es para enteros muuuy grandes, checa todo lo que puedes leer con los especificadores de formato :)

      Delete

¡Hey, gracias por tu comentario! No seas anónimo, inicia sesión para que te responda más fácilmente.