CodeGym /Cursos /C++ SELF /Entrada de linhas — std::getline

Entrada de linhas — std::getline

C++ SELF
Nível 2, Lição 4
Disponível

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.

Ideia chave: std::cin >> lê "uma palavra/número" (token), enquanto std::getline lê a linha inteira até o fim de linha.

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.

1
Tarefa
C++ SELF, nível 2, lição 4
Bloqueado
Colchetes do chat
Colchetes do chat
1
Tarefa
C++ SELF, nível 2, lição 4
Bloqueado
Comentário vazio
Comentário vazio
1
Tarefa
C++ SELF, nível 2, lição 4
Bloqueado
Número e frase
Número e frase
1
Tarefa
C++ SELF, nível 2, lição 4
Bloqueado
Endereço a partir de linhas
Endereço a partir de linhas
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION