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 caracter '\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 dinâmicamente. 
// 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 oportunidadde 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 subseqüentes. A função sscanf admite
// caracteres brancos -- mas nenhum outro tipo de caracter 
// -- 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 ("Caracter 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.

Argumentos na linha de comando

A função main, como qualquer outra função, admite argumentos.  Eles são conhecidos como "argumentos na linha de comando" (= command-line arguments).  O primeiro argumento é um inteiro que dá o número de argumentos.  O segundo, é um vetor de strings.   A função main deve ser especificada assim:

int main (int numargs, char *arg[]) {
   . . . 
} 

Se o nome do programa é xxx e digitarmos a linha de comando

xxx a  bb   ccc 2222 

então numargs terá valor 5 e os elementos de arg terão os seguintes valores:

Exemplo

O seguinte programa calcula a média dos números fornecidos como argumentos na linha de comando.

#include <stdio.h>
#include <stdlib.h>

int main (int numargs, char *arg[]) {
   int soma, n;
   soma = 0;
   for (i = 1; i < numargs; i++) {
      soma += atoi (arg[i]);
   }
   n = numargs - 1;
   printf ("média = %.2f\n", (double) soma / n);
   return EXIT_SUCCESS;
} 

Se o nome do programa for xxx e digitarmos a linha de comando

xxx +22  33 -11 +44

obteremos a resposta

média = 22.00

Outro exemplo

O seguinte programa imprime uma tabela de conversão de graus Celsius para graus Fahrenheit ou vice-versa. O usuário especifica a direção da conversão bem como o início e o fim da tabela.

#include <stdio.h>
#include <stdlib.h>

/* Programa temperatura
// --------------------
// Digite 
//         temperatura c-f 10 40
//
// para obter uma tabela de conversão de graus Celsius em graus
// Fahrenheit. A primeira coluna começará com 10 graus Celsius
// e andará em passos de 1 grau até 40 graus Celsius. A segunda
// coluna trará a correspondente temperatura em graus Fahrenheit.
// Troque "c-f" por "f-c" para obter a tabela de conversão de
// graus Fahrenheit em graus Celsius.
*/
int main (int numargs, char *arg[]) {
   int inf, sup;
   if (numargs != 4) {
      printf ("Número de argumentos errado.\n");
      return EXIT_FAILURE;
   }
   inf = atoi (arg[2]);
   sup = atoi (arg[3]);
   if (strcmp (arg[1], "c-f") == 0) {
      int c;
      printf("Celsius Fahrenheit\n");
      for (c = inf; c <= sup; c += 1) 
         printf("%7d %10.2f\n", c, 9.0 / 5.0 * c + 32);
      return EXIT_SUCCESS;
   }
   if (strcmp (arg[1], "f-c") == 0) {
      int f;
      printf("Fahrenheit  Celsius\n");
      for (f = inf; f <= sup; f += 1) 
         printf("%10d %8.2f\n", f, 5.0 * (f - 32.0) / 9.0);
      return EXIT_SUCCESS;
   }
   return EXIT_FAILURE;
} 

 

 


URL of this site: www.ime.usp.br/~pf/algoritmos/
1998 | Last modified: Wed Aug 16 12:10:08 BRT 2006
Paulo Feofiloff
IME-USP