Projeto de Algoritmos

"Entrada" e "saída": parte 2

A função scanf da biblioteca stdio é complexa e difícil de usar.  Eric Roberts (The Art and Science of C) escreveu algumas funções "de entrada" mais amistosas. Essas funções estão na biblioteca simpio.

Leitura de uma linha de um arquivo

A principal função da biblioteca simpio é ReadLline, que é capaz de ler uma linha de comprimento arbitrário.  Veja a seguir uma versão ligeiramente adaptada da função, que chamaremos readLine.  Ela substitui, com grande vantagem, a função fgets da biblioteca stdio.

#include <string.h>
#include <stdlib.h>

typedef char *string;

/* A função readLine lê uma linha de texto a partir da 
// posição corrente do arquivo infile e devolve o conteúdo
// da linha como uma string. O caractere '\n' que sinaliza 
// o fim da linha não é armazenado como parte da string. 
// A função readLine devolve NULL se a posição corrente 
// estiver no fim do arquivo. Uso típico da função: 
//                s = readLine (infile);
// Nota de implementação: A função transfere caracteres 
// do arquivo infile para um buffer alocado dinamicamente. 
// Se o buffer ficar cheio antes que o fim da linha tenha 
// sido atingido, um novo buffer é alocado com o dobro do 
// tamanho do anterior. 
// Esta função foi copiada, com adaptações, da biblioteca 
// simpio de Eric Roberts.
*/

string readLine (FILE *infile)
{
   string line, nline;
   int n, ch, size;
   
   n = 0;
   size = 120;
   line = mallocX (size + 1);
   while ((ch = getc (infile)) != '\n' && ch != EOF) {
      if (n == size) {
         size *= 2;
         nline = (string) mallocX (size + 1);
         strncpy (nline, line, n);
         free (line);
         line = nline;
      }
      line[n++] = ch;
   }
   if (n == 0 && ch == EOF) {
      free (line);
      return NULL;
   }
   line[n] = '\0';
   nline = (string) mallocX (n + 1);
   strcpy (nline, line);
   free (line);
   return nline;
}

É claro que a função readLine supõe, implicitamente, que a linha lida não contém caracteres nulos; essa hipótese é perfeitamente razoável. 

Leitura de uma linha do teclado

Para ler uma linha do teclado, basta invocar  readLine (stdin).  Se você tem certeza de que a linha de texto terá menos que 100 caracteres, pode se contentar com a seguinte versão simplificada de readLine:

string getLine (void) {
   string line;
   int n, ch;
   
   n = 0;
   line = mallocX (100+1);
   while ((ch = getc (stdin)) != '\n') {
      if (n >= 100) {
         free (line);
         exit (EXIT_FAILURE);
      }
      line[n++] = ch;
   }
   line[n] = '\0';
   return line;
}

Leitura de um inteiro

A função getInteger extrai um número inteiro de uma linha digitada no teclado. Ela usa a função readLine discutida acima e a função sscanf da biblioteca stdio.

/* A função getLine lê uma linha de texto do teclado,
// extrai dela um número inteiro e devolve o inteiro 
// extraído. Se não puder extrair um inteiro ou se a linha
// contiver um ou mais caracteres não brancos depois do 
// número na linha, o usuário tem a oportunidade de tentar
// de novo. Uso típico:
//                       i = getInteger();
// Note de implementação: A função lê uma linha e em seguida
// usa sscanf para extrair dela um inteiro. Ler uma linha 
// completa é essencial para que a função possa se recobrar 
// de um eventual erro de digitação do usuário; em caso 
// contrário, os caracteres depois da ocorrência do erro 
// permaneceriam no buffer de entrada e confundiriam as 
// operações de entrada subsequentes. A função sscanf admite
// caracteres brancos -- mas nenhum outro tipo de caractere 
// -- antes e depois do número inteiro.
// Esta função foi copiada, com adaptações, da biblioteca 
// simpio de Eric Roberts.
*/
int getInteger (void)
{
   string line;
   int value;
   char termch;
   
   while (TRUE) {
      line = readLine (stdin);
      switch (sscanf (line, " %d %c", &value, &termch)) {
         case 1:
            free (line);
            return value;
         case 2:
            printf ("Caractere inesperado: '%c'\n", termch);
            break;
         default:
            printf ("Digite um inteiro, por favor\n");
            break;
      }
      free (line);
      printf ("Tente de novo: ");
   }
}

Esta função pode ser facilmente adaptada para ler um long int ou um double.

 

 


URL of this site: www.ime.usp.br/~pf/algoritmos/
1998 | Last modified: Tue Jan 18 13:13:22 BRST 2011
Paulo Feofiloff
IME-USP

Valid HTML 4.01 Transitional    Valid CSS!