1. Conhecendo std::getline
Se você acabou de aprender std::cin >>, pode parecer que ele faz tudo: digita-se uma "palavra", digita-se um número, tudo funciona. Mas até o momento em que o usuário digita uma frase, um nome completo, o título de um livro ou um endereço — ou seja, texto com espaços. Aí o operador >> de repente se comporta como um robô literal demais: vê um espaço e decide que "pronto, a palavra acabou, eu paro aqui".
Imagine que std::cin >> é uma catraca do metrô: ela deixa passar exatamente um passageiro (token) e fecha no primeiro "obstáculo" como espaço ou '\n'. E std::getline é a porta do vagão: você entra inteiro, com todas as malas-espaços, e ninguém corta seu sobrenome no meio.
Como funciona std::getline
Quando você quer ler a linha inteira, incluindo espaços, precisa de std::getline. É uma função da biblioteca padrão, normalmente usada junto com std::string. Importante: a linha é lida até o caractere de nova linha '\n', mas o próprio '\n' não entra no resultado — ele é a fronteira, não parte do texto.
O padrão mínimo fica assim:
#include <iostream>
#include <string>
int main() {
std::string line;
std::getline(std::cin, line);
std::cout << "Line: " << line << '\n';
}
Aqui há alguns pontos muito importantes.
Primeiro, std::getline pode ler até mesmo uma linha vazia — isso não é um erro nem "quebrou", é uma entrada perfeitamente legal.
Segundo, std::getline não teme espaços: se o usuário digitar Ivan Ivanov, a string permanecerá Ivan Ivanov, não virará apenas Ivan.
Para ver os limites mais claramente (especialmente quando a linha está vazia), é útil imprimir a linha entre colchetes:
#include <iostream>
#include <string>
int main() {
std::string line;
std::getline(std::cin, line);
std::cout << "[" << line << "]\n"; // por exemplo: [Hello world]
}
2. Linhas vazias e como percebê-las
Uma linha vazia é quando o usuário simplesmente pressionou Enter e não digitou nenhum caractere. Iniciantes frequentemente interpretam isso como "a getline não funciona", mas na verdade é apenas mais uma string, com comprimento 0. Em programação, vazio também é dado (às vezes até o mais honesto).
Vamos fazer um exemplo que mostre claramente o tamanho da linha. Assim você distingue com certeza "vazio" de "não lido":
#include <iostream>
#include <string>
int main() {
std::string line;
std::getline(std::cin, line);
std::cout << "Text=[" << line << "]\n";
std::cout << "Size=" << line.size() << '\n'; // Size=0 para string vazia
}
Observe: line.size() retorna o número de caracteres. Se o usuário digitou Hi, o tamanho será 2. Se ele apenas pressionou Enter — será 0.
Linhas vazias podem aparecer em dois cenários principais.
- Primeiro — o usuário realmente digitou uma linha vazia (pressionou Enter).
- Segundo — mais traiçoeiro: você misturou std::cin >> com std::getline, e getline pegou o "resto" do nova-linha.
É como se você fosse buscar uma pizza e trouxessem a caixa... vazia, porque alguém já comeu a pizza na aula anterior. Agora vamos ver essa história.
3. Armadilha após std::cin >>: o resto da nova linha
Quando std::cin >> lê um token, ele pega caracteres até o espaço/tab/enter mais próximo. Detalhe importante: o separador (por exemplo, '\n') permanece no fluxo de entrada. Ou seja, condicionalmente falando, o "cursor de leitura" parou bem antes do '\n'.
E std::getline funciona exatamente assim: "leio até '\n'". Se o próximo caractere não lido na entrada é imediatamente '\n', então getline pensa: "Ah, o fim da linha já está aqui" e devolve uma string vazia.
Vejamos um cenário típico que confunde:
- o usuário digita a idade 25 e pressiona Enter
- em seguida digita o nome Ivan Ivanov e pressiona Enter
Nos dados de entrada isso aparece assim (o caractere \n é o Enter):
25\n
Ivan Ivanov\n
Agora o código:
#include <iostream>
#include <string>
int main() {
int age = 0;
std::string name;
std::cin >> age;
std::getline(std::cin, name); // armadilha!
std::cout << "Age=" << age << '\n';
std::cout << "Name=[" << name << "]\n"; // frequentemente vazio: []
}
Saída muito provável será:
Age=25
Name=[]
E isso não é "C++ ruim", é apenas consequência de o '\n' após o número ter permanecido na entrada, e getline o "comer" imediatamente como fim de linha.
Mini‑esquema: o que acontece no fluxo de entrada
Imagine a entrada como uma fita, e a leitura como um ponteiro na posição atual:
flowchart TD
A["Entrada: 25 seguido de Ivan Ivanov"] --> B["cin >> age lê 25"]
B --> C["Na entrada resta o caractere de nova linha e Ivan Ivanov"]
C --> D["getline vê primeiro o caractere de nova linha"]
D --> E["getline retorna string vazia"]
Isso é a tal "mágica" que na verdade é só mecânica. E a boa notícia: a solução também é um truque mecânico simples.
4. Como misturar >> e getline
Quando você precisa primeiro ler algo com std::cin >> (por exemplo, um número) e depois uma linha inteira com std::getline, a maneira mais simples de estabilizar o comportamento é fazer um getline adicional para uma variável-dummy, para consumir o resto da linha (normalmente esse é o '\n').
Aqui está a técnica canônica:
#include <iostream>
#include <string>
int main() {
int age = 0;
std::string dummy;
std::string name;
std::cin >> age;
std::getline(std::cin, dummy); // consumiu o restante '\n'
std::getline(std::cin, name); // agora lemos a linha real
std::cout << "Age=" << age << '\n';
std::cout << "Name=[" << name << "]\n";
}
Agora, se o usuário digitar:
25
Ivan Ivanov
a saída será a esperada:
Age=25
Name=[Ivan Ivanov]
Por que isso funciona? Porque o "getline de transição" lê o que restou após o >> até o fim da linha. Na maioria dos casos isso é somente um '\n', mas a lógica funciona também em casos mais complexos (por exemplo, se havia espaços após o número).
5. Várias chamadas getline em sequência
Quando você já optou por std::getline, ler várias linhas em sequência é muito prático: cada linha é uma chamada. E aí não existe o problema do "resto de '\n'", porque getline lê até '\n' e posiciona o fluxo na próxima linha.
Suponha que queremos ler "cidade" e "rua" (ambas linhas podem conter espaços):
#include <iostream>
#include <string>
int main() {
std::string city;
std::string street;
std::getline(std::cin, city);
std::getline(std::cin, street);
std::cout << "City=[" << city << "]\n";
std::cout << "Street=[" << street << "]\n";
}
Se o usuário digitar:
New York
5th Avenue
a aplicação lerá honestamente ambas as linhas completas.
É importante sentir a diferença: se você tentasse fazer isso com std::cin >>, New York viraria New, e York "cairia" na próxima variável. Às vezes isso é desejável (quando o formato é estritamente tokenizado), mas para texto humano geralmente queremos getline.
6. Mini‑aplicativo "Questionário"
Vamos escrever um pequeno aplicativo de console no estilo "questionário": o programa faz perguntas e imprime o que o usuário digitou. Hoje vamos melhorar: aprender a ler o nome completo inteiro, não apenas a primeira palavra.
Primeiro — a versão que parece lógica, mas falha (mostramos a armadilha para depois evitá-la):
#include <iostream>
#include <string>
int main() {
int age = 0;
std::string fullName;
std::cout << "Enter age: ";
std::cin >> age;
std::cout << "Enter full name: ";
std::getline(std::cin, fullName); // frequentemente vazio
std::cout << "Age=" << age << '\n';
std::cout << "Full name=[" << fullName << "]\n";
}
Se a entrada for:
25
Ivan Ivanov
então fullName frequentemente ficará vazio. E o usuário vai olhar para você como alguém que "pediu o nome — e logo em seguida o ignorou". Embaraçoso.
Agora a versão correta com getline:
#include <iostream>
#include <string>
int main() {
int age = 0;
std::string dummy;
std::string fullName;
std::cout << "Enter age: ";
std::cin >> age;
std::getline(std::cin, dummy); // consumiu '\n' após o número
std::cout << "Enter full name: ";
std::getline(std::cin, fullName);
std::cout << "Age=" << age << '\n'; // Age=25
std::cout << "Full name=[" << fullName << "]\n"; // Full name=[Ivan Ivanov]
}
Isso já se parece com um programa que você pode confiar para entrada de dados (pelo menos se o usuário digitar "como esperado").
Pequeno bônus: tamanho da linha como "sensor"
Às vezes é útil, especialmente em aulas, adicionar um "sensor":
#include <iostream>
#include <string>
int main() {
std::string line;
std::getline(std::cin, line);
std::cout << "Line=[" << line << "]\n";
std::cout << "Len=" << line.size() << '\n'; // Len=...
}
Assim você literalmente vê: a linha está vazia ou não. Em programas reais isso normalmente não é feito, mas para depuração e ensino — ajuda bastante.
7. Erros típicos ao trabalhar com std::getline
Erro nº 1: esperar que std::getline "não possa" retornar uma linha vazia.
Iniciantes costumam pensar: "Se eu chamei getline, então o usuário digitou algo". Mas o usuário pode ter pressionado Enter imediatamente, e então a string será honestamente vazia. Isso não é falha, são dados válidos, e o programa deve estar preparado para que line.size() seja 0.
Erro nº 2: misturar std::cin >> e std::getline sem a etapa de transição.
Clássico: leu um número com >>, depois chamou getline imediatamente — e obteve uma string vazia. O motivo é que após a leitura por token resta no fluxo um '\n', que getline interpreta como "fim de linha agora". Resolve-se com um getline adicional para uma variável-dummy.
Erro nº 3: não mostrar os limites da linha ao depurar e depois brigar com a realidade.
Quando a linha está vazia, um output com std::cout << line; parece que "nada aconteceu". É fácil começar a culpar o compilador, a IDE, as fases da Lua e o Wi‑Fi do vizinho. Na verdade basta imprimir como "[" + line + "]", para ver: a linha está realmente vazia, e aí faz sentido investigar a entrada.
Erro nº 4: confundir '\n' com "\\n".
'\n' é um único caractere de nova linha, que vem ao pressionar Enter (e que getline usa como limite). Já "\\n" são dois caracteres: barra invertida e letra n, ou seja, apenas texto \n. Se confundir os dois, pode levar tempo até entender por que "eu vi \n" mas getline se comporta diferente.
Erro nº 5: pensar que std::getline é um ">> melhorado" e ler tudo com ele sem entender o formato.
getline é realmente conveniente para texto humano, mas ele lê "até o fim da linha". Se o formato de entrada é baseado em tokens (por exemplo, números separados por espaços), getline pode não ser a ferramenta adequada. Bom estilo é entender o formato de entrada antes de escolher entre >> e getline.
GO TO FULL VERSION