Esta página descreve superficialmente as funções "de entrada" (= input) e "de saída" (= output) mais importantes da linguagem C. Todas estão na biblioteca stdio. Portanto, o seu programa deve ter um
#include <stdio.h>
para usar essas funções.
A função printf (= print formatted) exibe na tela do monitor uma lista "formatada" de números, caracteres, strings etc. O primeiro argumento da função é uma string que especifica o formato da impressão.
A função scanf (= scan format) lê do teclado e "formata" uma lista de números, caracteres, strings etc. O primeiro argumento da função é uma string que especifica o formato da lista a ser lida. Os demais argumentos são os endereços das variáveis onde os valores lidos serão armazenados. A função trata todos os brancos como se fossem ' '. Eis um exemplo:
#include <stdio.h>
#include <stdlib.h>
int main( void) {
int a, b;
double media;
scanf( "%d %d", &a, &b);
media = (a + b) / 2.0;
printf( "A média de %d e %d é %f\n", a, b, media);
return EXIT_SUCCESS;
}
Supondo que o nome do programa é prog, teremos o seguinte resultado (o computador escreve em vermelho e o usuário em azul):
prompt> prog 222 333 A média de 222 e 333 é 277.500000 prompt>
Um arquivo (= file) é uma sequência de bytes que reside em um disco magnético. Abstratamente, um arquivo tem estrutura semelhante à memória do computador. Mas, ao contrário do que acontece com a memória, os bytes de um arquivo não podem ser endereçados individualmente. Assim, o acesso a um arquivo é estritamente sequencial: para chegar ao 5º byte é preciso passar pelo 1º, 2º, 3º e 4º bytes.
Para que um programa possa manipular um arquivo, é preciso associar a ele uma variável do tipo FILE (esse tipo está definido no arquivo-interface stdio.h). A operação de associação é conhecida como "abertura" do arquivo e é executada pela função fopen (= file open). O primeiro argumento da função é o nome do arquivo e o segundo argumento é "r" ou "w" para indicar se o arquivo deve ser aberto "para leitura" (= read) ou "para escrita" (= write). A função devolve o endereço de um FILE (ou NULL, se não encontra o arquivo especificado).
Depois de usar o arquivo, é preciso "fechá-lo" com a função fclose (= file close).
Exemplo: Digamos que o arquivo dados.txt contém uma sequência de números inteiros separados por brancos. O programa abaixo calcula a média dos números. Para ler o arquivo, o programa usa a função fscanf (abreviatura de file scanf):
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
int main( void) {
int x, n, k;
double soma;
FILE *entrada;
entrada = fopen( "dados.txt", "r");
if (entrada == NULL) {
printf( "\nNão encontrei arquivo\n");
exit( EXIT_FAILURE);
}
soma = n = 0;
while (TRUE) {
k = fscanf( entrada, "%d", &x);
if (k != 1) break;
soma += x;
n += 1;
}
fclose( entrada);
printf( "A média dos números é %f\n", soma / n);
return EXIT_SUCCESS;
}
A função fscanf, tal como a função scanf, devolve o número de objetos efetivamente lidos. O programa acima usa isso para detectar o fim do arquivo. A propósito: o programa supõe que o arquivo contém pelo menos um número!
O teclado é um "arquivo padrão de entrada" (= standard input). Ele está permanente "aberto" e é representado pela constante stdin. Portanto fscanf( stdin,...) equivale a scanf( ...).
Algo análogo acontece com as funções printf, fprintf e o "arquivo" stdout, que representa a tela do monitor.
A função mais básica de entrada de dados — mais básica que printf — é putc (= put character). Cada invocação da função grava um caractere no arquivo especificado. Se c é um caractere e f aponta um arquivo, putc( c, f) grava c no arquivo f. Por exemplo, putc( '*', stdout) exibe um * na tela do monitor.
A função correspondente de leitura de caracteres é getc (= get character). Cada chamada da função lê um caractere do arquivo especificado. Se f aponta um arquivo então getc( f) lê o próximo caractere do arquivo. Em particular, getc( stdin) lê o próximo caractere do teclado.
Exemplo: O programa abaixo lê uma linha de caracteres do teclado, armazena essa linha em um vetor e em seguida exibe esses caracteres na tela do monitor. Vamos supor que a linha tem no máximo 100 caracteres (incluindo o '\n' final):
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
int main( void) {
char linha[100];
int i, j;
j = 0;
while (TRUE) {
linha[j] = getc( stdin);
if (linha[j] == '\n') break;
j = j + 1;
}
for (i = 0; i <= j; i += 1)
putc( linha[i], stdout);
return EXIT_SUCCESS;
}
Outro exemplo: O programa abaixo lê o primeiro caractere do arquivo dados.txt e exibe esse caractere na tela do monitor:
#include <stdio.h>
#include <stdlib.h>
int main( void) {
char c; /* erro */
FILE *entrada;
entrada = fopen( "dados.txt", "r");
if (entrada == NULL) exit( EXIT_FAILURE);
c = getc( entrada);
fclose( entrada);
putc( c, stdout);
return EXIT_SUCCESS;
}
O program tem um defeito, que discutiremos a seguir.
Que acontece se getc tenta ler o próximo caractere de um arquivo que já acabou? É preciso que getc devolva algum tipo de "caractere inválido". Acontece que todos os 256 caracteres são "válidos"!
Para resolver o impasse, getc não devolve um char mas um int, pois o conjunto de valores de int contém o conjunto de valores de char e é maior que esse último. Se o arquivo tiver acabado, getc devolve um int que não possa ser confundido com um char. Mais especificamente, a função faz o seguinte:
Para ser mais exato, se o arquivo não tem mais caracteres a função devolve a constante EOF (= end of file), que está definida no arquivo-interface stdio.h. Em muitos computadores — mas não em todos! — o valor de EOF é −1.
Exemplo: O seguinte fragmento de código exibe o próximo caractere do arquivo a menos que estejamos no fim do arquivo:
int c;
c = getc( entrada);
if (c != EOF)
putc( c, stdout);
else
printf( "\nO arquivo terminou!");
(Se o arquivo de entrada for stdin, o fim do arquivo é produzido pela combinação de teclas Ctrl-D, que gera o caractere 4.)
A solução adotado por getc é uma boa lição de projeto de algoritmos: a função devolve um objeto que pertence a um superconjunto do conjunto em que estamos realmente interessados. Situações análogas acontecem em muitas outras ocasiões.
int main( void) {
FILE *entrada;
int c;
entrada = fopen( "dados.txt", "r");
while ((c = getc( entrada)) != EOF)
printf( "%c ", c);
fclose( entrada);
return EXIT_SUCCESS;
}
Que acontece se trocarmos int c por char c? Que acontece se trocarmos int c por unsigned char c?
Para ganhar inspiração, analise o comportamento do utilitário wc (abreviatura de word count).
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 é prog e digitarmos a linha de comando
prog 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 prog e digitarmos a linha de comando
prog +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;
}