A forma com que um programa em C++ se comunica com o mundo externo é através de entrada e saída de dados: o usuário fornece dados via teclado e o programa imprime mensagens na tela. Todos os programas vistos até agora lêem suas entradas do teclado e produzem suas saídas na tela.
Em C++ toda entrada e saída é feita com fluxos (streams) de caracteres organizados em linhas. Cada linha consiste de zero ou mais caracteres e termina com o caracter de final de linha. Pode haver até 254 caracteres em uma linha (incluindo o caracter de final de linha). Quando um programa inicia, o sistema operacional automaticamente define quem é a entrada padrão (geralmente o teclado) e quem é a saída padrão (geralmente a tela).
As facilidades de entrada e saída não fazem parte da linguagem C++ . O que existe é uma biblioteca padrão de classes e funções (métodos) para manipular a transferência de dados entre programa e os dispositivos (devices) de saída e entrada padrão: cin, cout, cin.get(), cin.put(), puts(), gets(). Estas classes e funções são declaradas no arquivo <iostream>. Existem funções úteis para conversão e teste de caracteres declaradas no arquivo <ctype.h>.
As funções de entrada e saída operam sobre streams (fluxos) de caracteres. Toda vez que uma função se entrada é chamada (por exemplo, cin, cin.get()) ela verifica pela próxima entrada disponível na entrada padrão (por exemplo, texto digitado no teclado). Cada vez que uma função de saída é chamada, ela entrega o dado para a saída padrão (por exemplo, a tela).
As funções para leitura da entrada padrão e para escrita na saída padrão que têm sido usadas até agora são:
int cin.get( void ); int cin.put( int );
char *gets(char *); int puts( char *);
int cin >> arg1 >> arg2 >> ...; int cout << arg1 << arg2 << ...;
Vamos discutir algumas funções de entrada de dados (diferente do
cin). A entrada de texto é considerada como um fluxo de
caratecteres. Um fluxo texto é uma sequência de caracteres
dividida em linhas; cada linha consiste de zero ou mais caracteres
seguido do caractere de nova linha ( \
n). Como
programador, você não quer se preocupar em como as linhas são
representadas fora do programa. Quem faz isso por você são funções de
uma biblioteca padrão.
Suponha que você queira ler um único caractere, sem fazer qualquer tipo de conversão para um tipo de dados específico (o que é feito por cin). Isso pode ser feito usando a função cin.get().
A função cin.get() lê o caracter do teclado e mostra o que foi digitado na tela.
#include <iostream> using namespace std; int main() { char ch; cout << "Digite algum caracter: "; ch = cin.get(); cout << "\n A tecla pressionada eh " << ch << endl; }
O Resultado deste programa na tela é:
Digite algum caracter: A A tecla pressionada eh A.
A função cin.put() aceita um argumento de entrada, cujo valor será impresso como caracter:
#include <iostream> using namespace std; int main() { char ch; cout << "Digite algum caracter: "; ch = cin.get(); cin.put(ch); }
cin.get() é uma função vinculada à primitiva principal de entrada
cin. Cada vez que é chamada, esta função lê um caractere
teclado; cin.get começa a ler depois que a tecla é
digitada no final de uma sequência de caracteres (dizemos que a entrada
para a função cin.get() está no fluxo de entrada). A função
cin.get() retorna um valor, o caractere lido (mais precisamente,
o código inteiro ASCII correspondente ao caractere).
Vejamos o que acontece quando um programa trivial é executado.
#include <iostream> using namespace std; int main(){ char ch; ch = cin.get(); }
cin.get() obtém sua entrada do teclado. Portanto, quando o
programa acima é executado, o programa espera que o usuário digite
alguma coisa. Cada caractere digitado é mostrado no monitor. O
usuário pode digitar diversos caracteres na mesma linha, inclusive backspace para corrigir caracteres já digitados. No momento que ele
teclar , o primeiro caractere da sequência digitada é o
resultado da função cin.get(). Portanto, na
instrução do programa acima o caractere (ou melhor, o seu
código ASCII) é atribuído a variável ch.
Note que o usuário pode ter digitado diversos caracteres antes de
teclar
, mas a função cin.get() só
começará a ler o que foi digitado depois que for teclado
.
Além disso, com uma chamada da função cin.get() só
o primeiro caractere da sequência digitada é lida.
Você deve saber que o caractere de nova linha, \n
, que tem o
código ASCII 10, é automaticamente adicionado na sequência de
caracteres de entrada quando o é teclado. Isso não tem
importância quando a função cin.get() é chamada uma única
vez, mas isto pode causar problemas quando ele é usado dentro de um
laço.
No inicício de qualquer programa que usa cin.get(), você deve incluir
#include <iostream>
using namespace std;
Esta diretiva do pré-processador diz ao compilador para incluir informações sobre cin, cin.get() e EOF (mais sobre EOF adiante.).
Considere o seguinte programa:
#include <iostream> using namespace std; int main(){ char ch; cout << "Entre com uma letra: "; ch = cin.get(); if( ch < 'A' || ch > 'z' ) cout << "Voce nao teclou uma letra!"; else cout << "Voce teclou " << ch << ", e seu codigo ASCII eh " << (int) ch << endl; }
Um exemplo da execução do programa:
Entre com uma letra: A Voce teclou A, e seu codigo ASCII eh 65.
No exemplo de execução acima o usuário teclou A e depois .
Outro exemplo de execução do programa:
Entre com uma letra: AbcD Voce teclou A, e seu codigo ASCII eh 65.
Neste caso o usuário digitou quatro caracteres e depois teclou .
Embora quatro caracteres tenham sido digitados, somente uma chamada a
função cin.get() foi feita pelo programa, portanto só um
caractere foi lido. O valor atribuído ao argumento da função é o código
ASCII do primeiro caractere lido.
O tipo do resultado da função cin.get() é int e não char. O valor retornado pela função é o código ASCII do caractere lido.
Frequentemente quando você está digitando a entrada para o programa,
você quer dizer ao programa que você terminou de digitar o que queria.
Em ambiente Unix, digitando ^D
(segure a tecla de
Ctrl e pressione D) você diz ao programa que terminou a
entrada do programa. Em ambiente MS-Windows, você faz isto digitando
^Z
(segure a tecla de Ctrl e pressione Z).
Isto envia uma indicação para a função cin.get(). Quando isso ocorre, o valor de ch depois de executar ch = cin.get(); será um valor especial do tipo inteiro chamado EOF (que significa end of file - final do arquivo).
Considere o seguinte programa exemplo que conta o número de caracteres digitados (incluindo o caractere de “próxima linha”):
#include <iostream> using namespace std; int main() { int total = 0; char ch; // Le o proximo caractere em ch e pára quando encontrar // final do arquivo ch = cin.get(); while( ! cin.eof() ) { total++; ch = cin.get(); } cout << endl << total << " caracteres digitados" << endl; }
Só para esclarecer: você deve teclar depois de entrar com o
comando
^D
(ou ^Z
no MS-Windows).
(Observação: nesta seção, espaços em branco são relevantes e
são mostrados como )
Quando você executa um programa, cada caractere que você digita é lido
e considerado como parte do fluxo de entrada. Por exemplo,
quando você usa cin.get(), você deve teclar no final.
Como mencionado anteriormente, o primeiro caractere digitado é lido
pelo cin.get(). Mas, o caractere de nova linha continua no fluxo
de entrada (porque você teclou
).
De qualquer forma, se você executar um cin.get() depois de um cin ou de um cin.get() você lerá o caractere de nova linha deixado no fluxo de entrada.
Da mesma forma, quando você usa cin para ler informações, ele
somente lê o que é necessário. Se voce usar cin para ler um
número inteiro e digitar 42
(seguido de
), o cin lê
42
, mas deixa (e
o caractere de nova linha do
) no fluxo de entrada.
Outro caso “problemático” é quando o cin é usado num laço. Se você digitar um valor do tipo errado, o cin lerá o valor errado e a execução do laço continuará na sentença após o cin . Na próxima iteração do laço o cin vai tentar ler novamente, mas o “lixo” deixado da iteração anterior ainda estará lá, e portanto a chamada corrente do cin também não dará certo. Este comportamento resultará num laço infinito (um laço que nunca termina), ou terminará e terá um resultado errado.
Há uma maneira simples de resolver este problema; toda vez que você usar cin.get() (para ler um caracter só) ou cin , você deve ler todo o “lixo” restante até o caractere de nova linha. Colocando as seguinte linhas após chamadas a cin.get() ou cin o problema é eliminado:
// Pula o restante da linha while( cin.get(c) != '\n' );
Note que isso não é necessário após todas as chamadas a cin.get() ou cin . Só depois daquelas chamadas que precedem cin.get() (ou cin ), especialmente em um laço.
Muitas vezes queremos em nossos programas que eles obtenham um certo tipo de dado do usuário (por exemplo, valores inteiros) mas queremos também tratar a condição em que o usuário digita um dado real ou texto no lugar, exigindo uma reentrada de dados.
O exemplo abaixo nos mostra como fazer isto, usando a sentença com cin como expressão de um if ou while.
#include <iostream> #include <cstdlib> #include <cmath> #include <cstring> using namespace std; void cleanInput() { char cc; if (cin.fail()) { cin.clear(); while (cin.get(cc) && cc != '\n'); } } void printStatInput() { cout << "\tGood: " << cin.good() << " Fail: " << cin.fail() << " Bad: " << cin.bad() << " EOF: " << cin.eof() << endl << endl; } int main () { int b=1111, c=2222, d=3333; float x=1.111, y=2.222; void * cinerr; cout << "b c d = " << b << " " << c << " " << d << endl; cout << "x y = " << x << " " << y << endl; while (! (cinerr = cin >> b)) { cleanInput(); cout << "cin 1 = " << cinerr << " b = " << b << endl; printStatInput(); cout << "Entrada 1: "; } cout << "** cin 1 = " << cinerr << " b = " << b << endl; while (! (cinerr = cin >> b >> c >> d)) { cleanInput(); cout << "cin 2 = " << cinerr << " b c d = " << b << " " << c << " " << d << endl; printStatInput(); cout << "Entrada 2: "; } cout << "** cin 2 = " << cinerr << " b c d = " << b << " " << c << " " << d << endl; cinerr = cin >> x; cout << "cin 3 = " << cinerr << " x = " << x << endl; printStatInput(); if (!cinerr) { /* Limpar condição de erro em cin, se houver. */ cout << "Limpando condições de erro de CIN" << endl; cin.clear(); printStatInput(); } cout << "Ultima entrada: "; cinerr = cin >> x >> y; cout << "cin 4 = " << cinerr << " x y = " << x << " " << y << endl; printStatInput(); return 0; }
cin » ... retorna um valor especial5. Se nulo, a entrada não foi aceita e o valor da variável em que houve erro fica inalterado. As variáveis posteriores na leitura em que houve erro também mantém seus valores inalterados. Execuções subsequentes de cin somente podem ser feitas após a execução de cin.clear(), para eliminar a condição de erro. Caso isto não seja feito, após o primeiro erro de leitura, todos os cin » ... subsequentes darão erro.
Também podem ocorrer problemas de conversão de tipos em cin. Observe o exemplo abaixo:
int b; float x; cin >> b; cin >> x;
Neste caso, se usuário digita um float (por exemplo, 3.7) no 1º cin, o 2o.º cin não solicitará dado: 'b' recebe 3, deixando os chars '.4' no buffer de leitura. o 2º cin, então, armazena direto 0.4 em 'x', não aguardando digitação do usuário. Note que neste caso, cin » ... não acusará erro (isto é, não retorna valor nulo).
Para formatar a saída de dados com cout, (por exemplo, restringir a quantidade de casas decimais mostradas, definir o tamanho máximo em caracteres, ou imprimir uma matriz de valores alinhados adequadamente pelas colunas) usam-se a função setw() e o método setf() (cout.setf(....)).
Os exemplos abaixo mostram como usar estes elementos.
#include <iostream> #include <iomanip> // Necessário para usar os manipuladores setw() using namespace std; int main() { int n1, n2, n3; int soma; cout << "Entre com 3 numeros inteiros: "; cin >> n1 >> n2 >> n3; soma = n1 + n2 + n3; cout << "Soma = " << soma << endl; /* Define impressão de números em ponto fixo e mostra sempre o ponto decimal seguido por zeros */ cout.setf (ios::fixed | ios::showpoint); /* Outros flags válidos para setf(): ios::fixed ios:scientific ios::showpoint ios::right ios::left */ /* Define quantidade de algarismos a serem exibidos após ponto decimal. Em alguns compiladores, pode indicar a quantidade de algarismos SIGNIFICATIVOS. */ cout.precision(2); // setw() fixa a largura do campo de saída. // Aplica-se apenas ao próximo item exibido na saída. // Necessário incluir <iomanip> (vide início do código) cout << "Media = " << setw(8) << soma / 3.0 << endl; cout << "Produto = " << n1 * n2 * n3 << endl; }
// Exemplo de array 2-D - taboada #include <iostream> #include <iomanip> // Necessário para usar os manipuladores setw() using namespace std; #define LIN 10 #define COL 10 int main() { int x; // numero da coluna int y; // numero da linha int taboada[LIN][COL]; // tabela de taboada // preenche a taboada y=0; while(y < LIN) { x=0; while(x < COL) { taboada[y][x] = y*x; x = x+1; } y = y+1; } cout << "\n Taboada de Multiplicacao\n"; // Imprime o numero das colunas cout << setw(6) << 0; x=1; while(x < COL) { cout << setw(3) << x; x = x+1; } cout << endl; // Imprime uma "linha horizontal" cout << " "; x=0; while (x < 3*COL) { cout << "-"; x = x+1; } cout << endl; // Imprime as linhas da tablea. // Cada linha a precedida pelo indice de linha e uma barra vertical y=0; while (y < LIN) { cout << setw(2) << y << "|"; x=0; while(x < COL) { cout << setw(3) << taboada[y][x]; x = x+1; } cout << endl; y = y+1; }