Entrada e saída com iostream
por Callahan WhitmoreEntenda o conceito
O cabeçalho <iostream> traz os fluxos padrão do C++: std::cout para escrever na tela, std::cin para ler o que o usuário digita e std::cerr para mensagens de erro. A saída usa o operador <<, que insere o valor no fluxo; a entrada usa >>, que extrai um valor do fluxo e o converte para o tipo da variável de destino (int, double, std::string...).
O >> pula espaços e quebras de linha antes do valor e para no primeiro espaço depois dele. Por isso, std::cin >> nome lê uma palavra só. Para ler uma linha inteira, com espaços, use std::getline(std::cin, texto). O cuidado está na mistura dos dois: o >> deixa no buffer o '\n' do Enter, e um getline logo depois leria uma linha vazia. Escrever std::getline(std::cin >> std::ws, texto) descarta esses espaços antes.
Quando o usuário digita algo que não combina com o tipo, como abc para um int, o fluxo entra em estado de falha e as leituras seguintes não acontecem. Teste com if (!std::cin) antes de usar os valores.
Para formatar a saída, <iomanip> oferece std::setw (largura do próximo valor), std::left e std::right (alinhamento), além de std::fixed e std::setprecision (casas decimais). Prefira '\n' para quebrar linha; std::endl também quebra, mas força o envio imediato (flush), o que é mais lento em saídas grandes.
std::cout << valorescreve estd::cin >> variavellê; os dois podem ser encadeados (std::cin >> a >> b;).- O
>>lê até o próximo espaço ou quebra de linha; para uma linha com espaços, usestd::getline. - Depois de um
>>, leia a linha comstd::getline(std::cin >> std::ws, texto)para descartar o'\n'que sobrou no buffer. - Se a conversão falhar (texto onde se esperava número), o fluxo fica em estado de falha: confira com
if (!std::cin)e mande o erro parastd::cerr. std::setwvale só para o próximo valor, enquantostd::left,std::right,std::fixedestd::setprecisioncontinuam valendo até serem trocados.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Caixa da padaria com cin e cout
// Caixa da padaria: lê quantidade e preço e mostra o total
#include <iostream>
int main() {
int quantidade = 0; // valor inicial evita lixo se a leitura falhar
double preco = 0.0;
// Sem '\n' no fim, a resposta é digitada na mesma linha da pergunta
std::cout << "Quantos pães? ";
std::cin >> quantidade; // >> converte o texto digitado em int
std::cout << "Preço de cada um (use ponto): ";
std::cin >> preco; // aqui o texto vira double
double total = quantidade * preco;
// Vários << encadeados montam uma linha só
std::cout << quantidade << " pães a R$ " << preco
<< " = R$ " << total << '\n';
// >> também encadeia: lê dois valores separados por espaço ou Enter
int mesa = 0;
int pessoas = 0;
std::cout << "Mesa e número de pessoas: ";
std::cin >> mesa >> pessoas;
std::cout << "Mesa " << mesa << " com " << pessoas << " pessoas\n";
return 0;
}
O programa faz uma pergunta com std::cout e lê a resposta com std::cin >>, que converte o texto digitado para o tipo da variável: quantidade vira int e preco vira double. Na última leitura, dois >> encadeados pegam a mesa e o número de pessoas, separados por espaço ou por Enter.
Com as respostas 8, 0.75 e 4 3, o programa imprime 8 pães a R$ 0.75 = R$ 6 e Mesa 4 com 3 pessoas. Repare que o total sai como 6, e não 6.00: sem std::fixed e std::setprecision, o std::cout omite os zeros à direita de um double.
02Cadastro de livro com getline e std::ws
// Cadastro no acervo: getline para textos com espaços
#include <iostream>
#include <string>
int main() {
std::string titulo;
std::string autor;
int ano = 0;
// >> pararia no primeiro espaço e leria só "O" de "O Cortiço"
std::cout << "Título: ";
std::getline(std::cin, titulo); // lê a linha inteira e descarta o '\n'
std::cout << "Ano de publicação: ";
std::cin >> ano; // lê o número, mas deixa o '\n' do Enter no buffer
// Sem std::ws, o getline acharia aquele '\n' e o autor ficaria vazio
std::cout << "Autor: ";
std::getline(std::cin >> std::ws, autor); // ws pula espaços e quebras
std::cout << "\nFicha do acervo\n";
std::cout << "Título: " << titulo << '\n';
std::cout << "Autor: " << autor << '\n';
std::cout << "Ano: " << ano << '\n';
// std::endl quebra a linha e força o envio imediato (flush)
std::cout << "Cadastro concluído." << std::endl;
return 0;
}
O título tem espaço, então é lido com std::getline, que guarda a linha inteira. Já o ano é lido com >>, que para depois do número e deixa o '\n' do Enter esperando no buffer. Se o autor fosse lido com std::getline(std::cin, autor), ele encontraria esse '\n' na hora e ficaria vazio, sem o usuário conseguir digitar nada.
std::cin >> std::ws resolve o problema: ele consome espaços e quebras de linha até o primeiro caractere visível, e só então o getline lê Aluísio Azevedo. A última linha usa std::endl, que quebra a linha e esvazia o buffer na hora; nas outras, '\n' basta.
03Ficha do torneio com validação e setw
// Ficha do torneio: valida a leitura e alinha a saída com setw
#include <iomanip> // std::setw, std::left, std::fixed, std::setprecision
#include <iostream>
#include <string>
int main() {
std::string jogador;
int vitorias = 0;
int derrotas = 0;
std::cout << "Jogador, vitórias e derrotas: ";
std::cin >> jogador >> vitorias >> derrotas;
// Se algo não for número, o fluxo entra em estado de falha
if (!std::cin) {
std::cerr << "Entrada inválida: use números inteiros\n";
return 1; // código diferente de 0 indica erro
}
const int partidas = vitorias + derrotas;
const double aproveitamento =
partidas > 0 ? 100.0 * vitorias / partidas : 0.0;
// setw vale só para o próximo valor; left e right ficam até serem trocados
std::cout << '\n' << std::left << std::setw(10) << "Jogador"
<< std::right << std::setw(4) << "V" << std::setw(4) << "D"
<< std::setw(9) << "Aprov." << '\n';
std::cout << std::left << std::setw(10) << jogador
<< std::right << std::setw(4) << vitorias << std::setw(4) << derrotas
<< std::fixed << std::setprecision(1)
<< std::setw(8) << aproveitamento << "%\n";
return 0;
}
Se o usuário digitar Kira sete 3, o >> não consegue transformar sete em int, o fluxo entra em estado de falha e !std::cin fica verdadeiro. A mensagem vai para std::cerr, a saída própria para erros, e o return 1 encerra o programa avisando que algo deu errado. Com Kira 7 3, a leitura funciona e o aproveitamento é 70.0.
Na tabela, std::setw(n) reserva n colunas só para o valor seguinte, por isso aparece antes de cada um. std::left alinha o nome à esquerda e std::right volta os números para a direita; esses dois, assim como std::fixed e std::setprecision(1), continuam valendo até serem trocados. Como cabeçalho e linha usam as mesmas larguras, as colunas ficam alinhadas.
Agora é com você
Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.
01Pontos do jogador em três fasesFácil
Leia o apelido de um jogador (uma palavra) e os pontos que ele fez em três fases, todos num único std::cin encadeado, e mostre os pontos e o total. Para conferir, digite Lia 120 85 140; a saída esperada é só o que o programa imprime, sem mensagens pedindo os dados.
- Ler o apelido em
std::stringe os pontos em três variáveisint. - Fazer a leitura com um único
std::cine quatro operadores>>encadeados. - Não imprimir mensagens pedindo os dados.
- Com a entrada
Lia 120 85 140, reproduzir exatamente a saída esperada.
#include <iostream>
#include <string>
int main() {
// Declare o apelido e os pontos das três fases
// Leia tudo com um único std::cin
// Mostre os pontos e o total
return 0;
}
Jogador: Lia
Pontos por fase: 120, 85 e 140
Total: 345
Ver dica
O >> não se importa se os valores vêm separados por espaço ou por Enter: cada um continua a leitura de onde o anterior parou.
Ver resposta
#include <iostream>
#include <string> // necessário para std::string
int main() {
std::string jogador;
int fase1 = 0;
int fase2 = 0;
int fase3 = 0;
// Um único cin encadeado lê as quatro informações, na ordem
std::cin >> jogador >> fase1 >> fase2 >> fase3;
int total = fase1 + fase2 + fase3;
std::cout << "Jogador: " << jogador << '\n';
std::cout << "Pontos por fase: " << fase1 << ", " << fase2 << " e " << fase3 << '\n';
std::cout << "Total: " << total << '\n';
return 0;
}
Entrada digitada: Lia 120 85 140.
Passo a passo
- As variáveis começam com valor (
0nosint), assim nada de lixo de memória aparece se a leitura falhar. std::cin >> jogadorlê a primeira palavra (Lia) e para no espaço; por isso o apelido precisa ser uma palavra só.- Os três
>>seguintes pulam o espaço e convertem120,85e140emint, porque esse é o tipo das variáveis. - Encadear
>>é o mesmo que escrever quatro leituras seguidas: cada uma continua de onde a anterior parou. - A soma é feita entre inteiros e guardada em
total. - Cada
std::coutjunta textos e valores com<<e termina com'\n'; não há mensagem pedindo os dados, então a saída tem só o resultado.
Por que funciona
O >> lê do fluxo de entrada até o próximo espaço, tabulação ou quebra de linha e converte o pedaço lido para o tipo da variável de destino. Como espaços e Enter servem igualmente de separador, o programa funciona tanto com tudo numa linha quanto com um valor por linha.
Erros comuns
- Esquecer o
#include <string>: o código pode até compilar em alguns compiladores, porque<iostream>às vezes inclui<string>por tabela, mas não há garantia. Inclua sempre. - Inverter a seta:
std::cin << fase1;não compila. Na entrada a seta aponta para a variável (>>), indicando para onde o dado vai. - Digitar um nome com espaço: com
Lia Souza 120 85 140, ojogadorrecebeLia, ofase1tenta lerSouza, a leitura falha e os pontos ficam zerados. Para textos com espaço, usestd::getline.
Outra forma de resolver
Dá para ler cada valor num std::cin separado (std::cin >> jogador; std::cin >> fase1; ...). O resultado é o mesmo; o encadeamento só deixa o código mais curto quando os dados chegam juntos.
Saída esperada
Jogador: Lia
Pontos por fase: 120, 85 e 140
Total: 345
02Etiqueta de estoque com getlineMédio
Leia, nesta ordem e uma por linha, a quantidade de um produto em estoque, o nome dele (que pode ter espaços) e o preço unitário, e mostre a etiqueta com o valor total em estoque. Para conferir, digite 12, Caneca de cerâmica azul e 24.90, sem mensagens pedindo os dados.
- Ler a quantidade com
>>, o nome comstd::getlinee o preço com>>. - Usar
std::wspara que o nome não seja lido como uma linha vazia. - Mostrar os valores em reais com
std::fixedestd::setprecision(2). - Com a entrada indicada, reproduzir exatamente a saída esperada.
#include <iomanip>
#include <iostream>
#include <string>
int main() {
int quantidade = 0;
std::string produto;
double preco = 0.0;
// Leia a quantidade, o nome do produto e o preço
// Calcule e mostre a etiqueta
return 0;
}
Produto: Caneca de cerâmica azul
Quantidade: 12 unidades
Preço unitário: R$ 24.90
Valor em estoque: R$ 298.80
Ver dica
Pense no que sobra no buffer depois que o >> lê o número 12 e no que o getline faz quando a primeira coisa que encontra é uma quebra de linha.
Ver resposta
#include <iomanip> // std::fixed e std::setprecision
#include <iostream>
#include <string>
int main() {
int quantidade = 0;
std::string produto;
double preco = 0.0;
std::cin >> quantidade; // lê 12 e deixa o '\n' no buffer
std::getline(std::cin >> std::ws, produto); // ws descarta o '\n' antes da linha
std::cin >> preco; // >> pula sozinho a quebra de linha
double valorEstoque = quantidade * preco;
std::cout << "Produto: " << produto << '\n';
std::cout << "Quantidade: " << quantidade << " unidades\n";
std::cout << std::fixed << std::setprecision(2); // duas casas daqui em diante
std::cout << "Preço unitário: R$ " << preco << '\n';
std::cout << "Valor em estoque: R$ " << valorEstoque << '\n';
return 0;
}
Entrada digitada, uma informação por linha: 12, Caneca de cerâmica azul e 24.90.
Passo a passo
std::cin >> quantidade;converte12emint, mas o Enter digitado depois continua no buffer como'\n'.std::cin >> std::wsconsome esse'\n'(e qualquer espaço) antes dogetline.std::getline(..., produto)lê a linha inteira, com os espaços, e descarta o'\n'do final.std::cin >> preco;lê24.90; o>>já pula espaços e quebras sozinho, então não precisa destd::ws.quantidade * precopromove ointparadoublee dá 298.80.std::fixedcomstd::setprecision(2)vale para todos osdoubleimpressos depois; ointda quantidade, impresso antes, sai sem casas.
Por que funciona
O >> e o getline tratam a quebra de linha de forma diferente: o >> ignora espaços e quebras antes do valor, mas não consome a quebra que vem depois dele; o getline lê até o primeiro '\n' que encontrar, mesmo que ele esteja logo no início. O std::ws resolve o encontro dos dois, limpando o caminho antes da leitura da linha.
Erros comuns
getlinesemstd::wsdepois de>>:std::getline(std::cin, produto);lê uma linha vazia. O produto sai em branco e o>> precotenta lerCaneca, falha e deixa o preço em 0.- Usar
>>para o nome:std::cin >> produto;guarda sóCaneca, e o>> precotenta lerde. Linhas com espaço pedemgetline. - Vírgula no preço: digitar
24,90faz o>>ler apenas24e parar na vírgula. Ostd::cinusa ponto como separador decimal. std::fixedantes da quantidade: não estraga nada aqui, porqueintnão tem casas decimais, mas deixar a formatação perto dos valores que ela afeta facilita a leitura.
Outra forma de resolver
Em vez de std::ws, dá para descartar o resto da linha com std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); (de <limits>). Essa forma é preferível quando a linha do número pode ter lixo depois dele; para entradas bem formadas, o std::ws é mais curto.
Saída esperada
Produto: Caneca de cerâmica azul
Quantidade: 12 unidades
Preço unitário: R$ 24.90
Valor em estoque: R$ 298.80
03Cupom da padaria em colunasDesafio
Leia três itens de uma compra, um por linha no formato quantidade preço nome (o nome pode ter espaços), verifique se a leitura deu certo e imprima um cupom com colunas alinhadas, o total de unidades e o valor da compra. Para conferir, digite 2 4.50 Pão francês, 1 12.90 Queijo minas e 3 3.25 Iogurte natural.
- Ler a quantidade e o preço com
>>e o nome comstd::getline(std::cin >> std::ws, ...). - Se alguma leitura falhar, mostrar
Entrada inválidaemstd::cerre encerrar comreturn 1. - Alinhar quantidade, preço e total com
std::setw(larguras 3, 8 e 8), com o nome do item na última coluna. - Mostrar os valores com duas casas (
std::fixedestd::setprecision(2)) e, com a entrada indicada, reproduzir exatamente a saída esperada.
#include <iomanip>
#include <iostream>
#include <string>
int main() {
// Variáveis dos três itens: quantidade, preço e nome
// Leia as três linhas
// Verifique se a leitura deu certo
// Imprima o cupom em colunas
return 0;
}
Qtd Unit. Total Item
2 4.50 9.00 Pão francês
1 12.90 12.90 Queijo minas
3 3.25 9.75 Iogurte natural
Unidades: 6
Total da compra: R$ 31.65
Ver dica
Depois de ler os dois números da linha, ainda sobra um espaço antes do nome; e o fluxo guarda uma falha até o fim, então um único teste depois de todas as leituras basta.
Ver resposta
#include <iomanip> // std::setw, std::fixed e std::setprecision
#include <iostream>
#include <string>
int main() {
int qtd1 = 0;
int qtd2 = 0;
int qtd3 = 0;
double preco1 = 0.0;
double preco2 = 0.0;
double preco3 = 0.0;
std::string item1;
std::string item2;
std::string item3;
// Cada linha: quantidade, preço e o nome até o fim da linha
std::cin >> qtd1 >> preco1;
std::getline(std::cin >> std::ws, item1);
std::cin >> qtd2 >> preco2;
std::getline(std::cin >> std::ws, item2);
std::cin >> qtd3 >> preco3;
std::getline(std::cin >> std::ws, item3);
// Uma falha em qualquer leitura fica registrada no fluxo
if (!std::cin) {
std::cerr << "Entrada inválida\n";
return 1;
}
const double total1 = qtd1 * preco1;
const double total2 = qtd2 * preco2;
const double total3 = qtd3 * preco3;
std::cout << std::fixed << std::setprecision(2);
// Cabeçalho com as mesmas larguras das linhas; o nome fica por último
std::cout << std::setw(3) << "Qtd" << std::setw(8) << "Unit." << std::setw(8) << "Total" << " Item\n";
std::cout << std::setw(3) << qtd1 << std::setw(8) << preco1 << std::setw(8) << total1 << " " << item1 << '\n';
std::cout << std::setw(3) << qtd2 << std::setw(8) << preco2 << std::setw(8) << total2 << " " << item2 << '\n';
std::cout << std::setw(3) << qtd3 << std::setw(8) << preco3 << std::setw(8) << total3 << " " << item3 << '\n';
std::cout << "Unidades: " << qtd1 + qtd2 + qtd3 << '\n';
std::cout << "Total da compra: R$ " << total1 + total2 + total3 << '\n';
return 0;
}
Entrada digitada, uma linha por item: 2 4.50 Pão francês, 1 12.90 Queijo minas e 3 3.25 Iogurte natural.
Passo a passo
std::cin >> qtd1 >> preco1;lê os dois números do começo da linha e para logo antes do espaço que separa o preço do nome.std::getline(std::cin >> std::ws, item1);pula esse espaço e lê o resto da linha, com os espaços do nome (Pão francês), consumindo o'\n'.- As outras duas linhas repetem o mesmo par de leituras; o
>>da linha seguinte já ignora qualquer quebra que tenha sobrado. if (!std::cin)testa o fluxo uma vez só, depois de todas as leituras: quando uma falha, o fluxo fica em estado de falha e as leituras seguintes nem acontecem, então basta conferir no fim.- A mensagem de erro vai para
std::cerr, a saída de erros, e oreturn 1avisa a quem rodou o programa que algo deu errado. std::setw(n)reservancolunas e alinha o próximo valor à direita; ele precisa ser repetido antes de cada valor, porque vale para um só.- O cabeçalho usa as mesmas larguras (3, 8 e 8) que as linhas, e por isso as colunas ficam alinhadas.
- Com
std::fixedestd::setprecision(2), preços e totais saem com centavos; as quantidades e a soma das unidades, que sãoint, não mudam.
Por que funciona
A entrada mistura números e um texto com espaços na mesma linha. O >> resolve os números porque para no primeiro espaço, e o getline com std::ws pega o que sobrou da linha como um texto só. Na saída, std::setw transforma valores de tamanhos diferentes (4.50 e 12.90) em colunas de largura fixa.
O nome do item fica na última coluna de propósito: o std::setw conta bytes, e letras acentuadas como ã e ê ocupam 2 bytes em UTF-8. Numa coluna do meio, Pão francês desalinharia a tabela; no fim da linha, não há nada depois dele para desalinhar.
Erros comuns
- Ler o nome com
>>:std::cin >> qtd1 >> preco1 >> item1;guarda sóPão; a leitura seguinte tenta converterfrancêsemint, falha e o programa mostraEntrada inválida. - Um
setwpara a linha toda:std::cout << std::setw(8) << preco1 << total1;alinha só o preço; o total sai colado. Repitastd::setwantes de cada valor. - Testar o fluxo antes de ler tudo: conferir
!std::cinsó depois da primeira linha deixa as outras sem verificação. Teste depois da última leitura (ou após cada uma, se quiser mensagens específicas). - Mensagem de erro no
std::cout: funciona na tela, mas mistura o erro com o resultado quando a saída é redirecionada para um arquivo. Erros vão parastd::cerr.
Outra forma de resolver
Com C++20, std::format (de <format>) monta cada linha com larguras e casas na própria string: std::cout << std::format("{:3}{:8.2f}{:8.2f} {}\n", qtd1, preco1, total1, item1);. Ela é preferível quando o compilador já suporta C++20 e há muitas colunas; os manipuladores de <iomanip> funcionam em qualquer versão.
Saída esperada
Qtd Unit. Total Item
2 4.50 9.00 Pão francês
1 12.90 12.90 Queijo minas
3 3.25 9.75 Iogurte natural
Unidades: 6
Total da compra: R$ 31.65