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.
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.
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; }
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.
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:
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
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;
}