Atualizado pela última vez em fevereiro de 2021.
A entrada padrão e saída padrão são fluxos de dados usados para que não seja necessário dizer onde realizar as operações de leitura e escrita toda hora. Esse conceito permite que você, num programa, mande ler ou escrever, sem especificar exatamente de onde, e então a leitura será feita da entrada padrão ou, a escrita será feita na saída padrão.
Fluxos de dados são conjuntos de dados, sujeitos a operações de leitura e escrita sem posição associada. Isso quer dizer que um fluxo de dados é parecido com um arquivo, porém é mais genérico. Ler de um dado de um fluxo de dados implica em ler "o próximo" dado do conjunto. Podemos fazer uma analogia com uma fila. Um arquivo, por outro lado, não precisa ter esse conceito de sequência. Pode-se ler um dado numa posição de um arquivo e depois realizar uma leitura numa posição anterior.
Observe o programa em C++ a seguir.
#include <iostream>
using namespace std;
int main() {
cout << "Entre com o valor do primeiro numero: ";
float a;
cin >> a;
cout << "Entre com o valor do segundo numero: ";
float b;
cin >> b;
cout << "A soma e': " << a+b << endl;
return 0;
}
Este programa serve para calcular a soma de dois números. De onde é feita a leitura dos dois números? Se você respondeu: "do teclado", errou. O programa diz que os dados devem ser lidos de cin. Mas o que é cin? É a entrada padrão. E o que é a entrada padrão? É aquilo definido no início deste texto. Porém, a definição não explica exatamente de onde serão lidos os valores de a e b. O objetivo é esse mesmo. No momento da escrita do código acima, não se sabe de onde esses valores serão lidos. Não dá para saber apenas olhando o código. O dispositivo propriamente dito que vai ser usado para a leitura de valores só vai ser definido quando o programa começar a executar. O programa que mandar esse programa executar é que vai definir o que é exatamente a entrada padrão e a saída padrão. Isso permite que o programa mostrado some dois números lidos do teclado, ou de um arquivo, ou de conexão de rede ou ainda de dados produzidos por outro programa. O objetivo de mandar ler ou escrever em algo que não se sabe o que é, é a flexibilidade de definir essa coisa apenas quando for conveniente, sem necessidade de modificar ou de recompilar o programa apenas para mudar o fluxo de dados usado. É claro que nos cursos iniciais de programação, não estamos interessados em ficar alterando os dispositivos de entrada e saída padrão dos programas. Vamos apenas mostrar aqui que eles podem alterados.
O objetivo é ensinar o conceito de entrada e saída padrão, especialmente para que nossos alunos não fiquem pensando que cin é um comando de leitura, ou que cout é um comando de escrita, o que causa problemas quando se ensina o conceito de arquivos. Os comandos de escrita e leitura em C++ são respectivamente o << e o >>. Para decorar qual é qual, é útil enxergar os comandos como setas que ilustram a passagem de informação. Na leitura, a informação vai do fluxo de dados para a variável, e na escrita acontece o contrário.
Em outras linguagens, geralmente não é obrigatório informar nos comandos de leitura e escrita qual o fluxo de dados a ser usado. Quando o fluxo não é informado, usa-se a entrada padrão para as leituras e a saída padrão para as operações de escrita. Em C++ é obrigatório e por isso precisamos que variáveis que representem esses fluxos. Entretanto, nomes para entrada e saída padrão existem em qualquer linguagem.
Linguagem | entrada padrão | saída padrão |
---|---|---|
C++ | std::cin | std::cout |
C | stdin | stdout |
Python | sys.stdin | sys.stdout |
Java | System.in | System.out |
Para saber mais:
Vamos demostrar a flexibilidade do programa
fazendo ele somar dois números de um arquivo ao invés de ficar
esperando que digitem números no teclado. Usando um editor de textos,
crie um arquivo chamado dados com dois números:
45 78
Um interpretador de linha de comandos qualquer (bash, tcsh, cmd, etc.) oferece formas
para determinar a entrada e a saída padrão de um programa a ser
executado. Quase sempre o sinal de menor (<), depois do comando,
seguido de um nome de arquivo, torna o arquivo a entrada padrão
do programa executado. Assim, supondo que o programa que soma
dois números está compilado num arquivo chamado somar,
podemos mandar executar o comando:
./somar < dados
Nessa execução os dois números são lidos do arquivo dados,
não sendo necessário digitá-los, e o resultado é esse:
$ ./somar < dados
Entre com o valor do primeiro numero: Entre com o valor do segundo numero: A soma e': 123
$ _
No mundo real, programas que conversam com usuários usam interface gráfica, enquanto que programas sem interface gráfica evitam isso. Programas que usam interface de linha de comando geralmente recebem as informações de entrada (opções do usuário) na forma de parâmetros e os dados a serem processados geralmente ficam em arquivos. Porém não desejamos ensinar a passagem de parâmetros para programas logo no início do ensino de programação e o uso de arquivos é ensinado mas demora quase um semestre. Para os programas iniciais preferimos o desenvolvimento de programas que leem e escrevem dados como no exemplo acima, porém sem perder tempo "conversando" com o usuário. O programa deve simplesmente ler as entradas e somente as entradas, além de escrever as saídas e somente as saídas.
Isso é especialmente importante nos programas que serão enviados ao Dredd para correção. É muito difícil programar o Dredd para distinguir quais escritas são bate-papo sem importância e quais são aquelas que indicam as variáveis com resultado de processamento. Existem planos de deixar isso um pouco mais livre para o programador no futuro, porém, até lá não é permitido escrever coisas que não sejam respostas do problema.
Assim o programa anterior, sem escrita de instruções para o usuário fica:
#include <iostream>
using namespace std;
int main() {
float a, b;
cin >> a >> b;
cout << a+b << endl;
return 0;
}
O programa acima lê os dois números a serem somados, realiza a soma e escreve o resultado. Só o essencial. Assim devem ser os programas enviados ao Dredd.
Note também que o programa manda escrever um fim de linha depois de escrever o resultado. O Dredd não liga para isso, mas os professores olhando seu programa sim. Toda linha que seu programa escreve deve ser terminada com fim de linha para fins de legibilidade e elegância. Deixar uma linha sem terminar implica que ao usar seu programa num terminal junto com outros programas, o próximo programa que usar o terminal vai continuar a escrever de onde o seu programa parou, tudo grudado e difícil de entender. Eu sei que você se acostumou a executar seu programa apertando botãozinho no Geany, que automaticamente abre um terminal exclusivo para seu programa e ao final da execução aguarda você informar que o terminal já pode ser fechado, mas você não é todo mundo. Inclusive, é comum ver alunos enfrentando dificuldades por causa desse costume. Esquecer de fechar os terminais e depois não saber qual terminal mostra a última execução ou ainda fechar rapidamente por costume e depois ter que executar tudo de novo para tentar entender os erros ocorridos são situações comuns nas atividades práticas. Eu recomendo que você compile e execute seus programas usando um terminal para isso.
Note também que existe um comando return depois de mandar escrever o resultado. Em termos de linguagem, isso é opcional desde a versão de 1999 da linguagem C, que foi incorporado na próxima versão de C++ para manter a compatibilidade. Mesmo sendo opcional, recomendamos que escreva esse comando. O hábito de escrever vai ajudar a não esquecer dele quando você aprender modularização e vai te ajudar a entender como programas se comunicam entre si com códigos de erro quando você aprender sobre tratamento de erros. Omitir o return da função main só tem utilidade quando você aprender orientação a eventos, porque lá o término do programa não fica na função main.
Esta página é mantida por Bruno Schneider para a disciplina de IAlg