UFLA

🎓 Aula 08

Strings e uso do getline()

Prof. Paulo Rettore

Universidade Federal de Lavras

GAC124 — Introdução aos Algoritmos

🎯 Texto em C++

Uma string representa uma sequência de caracteres. Ela é prática para nomes, frases e mensagens.

Palavra

string nome = "Ana";

Frase

Também pode conter espaços.

Caracteres

Cada posição tem um índice.

Inclua <string> e use std::string ou using namespace std.

🔤 Strings × vetores de caracteres

string

Tipo da biblioteca C++ para textos. Conhece seu tamanho e oferece funções como find() e replace().

char[]

Vetor de caracteres. Para representar uma C-string, precisa terminar com o caractere nulo \0.

char letras1[4] = {'i', 'a', 'l', 'g'};       // vetor de char
char letras2[5] = {'i', 'a', 'l', 'g', '\0'};  // C-string

Sem \0, o vetor não informa onde o texto termina. Para as atividades da disciplina, prefira string quando não houver motivo para usar char[].

📏 Tamanho da sequência de caracteres

length()

Quantidade de caracteres da string.

size()

Faz a mesma contagem em uma string.

strlen()

Conta uma C-string até encontrar \0.

#include <cstring>

string nome = "IAlg";
char palavra[] = "UFLA";

cout << nome.length();   // 4
cout << nome.size();     // 4
cout << strlen(palavra); // 4

length() e size() são métodos de string; strlen() é uma função para vetores de caracteres terminados em \0.

🧱 Declaração e operações básicas

string nome = "Ana";
string sobrenome = "Silva";

string completo = nome + " " + sobrenome;
cout << completo;

completo[0] = 'a'; // altera uma posição

Tamanho

completo.size()

Índice

completo[0]

Concatenação

texto1 + texto2

🧰 Biblioteca <string>

Além de guardar texto, string oferece operações para localizar, remover e substituir partes da sequência.

#include <string>

std::string frase = "IAlg em C++";
size_t pos = frase.find("C++");
if (pos != std::string::npos)
    cout << "Encontrado na posição " << pos;

frase.replace(0, 4, "Aula"); // substitui "IAlg" por "Aula"
frase.erase(4, 3);            // remove " em"

Como interpretar: replace(posição, quantidade, novo texto). Como "IAlg" tem 4 caracteres, replace(0, 4, "Aula") produz "Aula em C++". Usar 0, 3 deixaria o g no texto.

find()

Busca um trecho e retorna sua posição.

erase()

Remove caracteres a partir de uma posição.

replace()

Troca um trecho por outro.

🔎 Quando a busca não encontra?

Funções como find() retornam uma posição quando encontram o trecho. Quando não encontram, retornam o marcador especial std::string::npos.

std::string frase = "IAlg em C++";
size_t pos = frase.find("Python");

if (pos == std::string::npos)
    cout << "Trecho não encontrado";

Encontrou

pos recebe um índice válido: 0, 1, 2...

Não encontrou

pos recebe std::string::npos, uma constante que significa “posição inexistente”.

Use pos != std::string::npos para testar sucesso. Não dependa do número interno da constante e não compare diretamente com -1.

⌨️ cin lê até o espaço

string nome;
cin >> nome;

Se a entrada for Paulo Rettore, o cin lê apenas Paulo.

O operador >> pula espaços no início e para no próximo espaço. Para ler uma linha inteira, use getline().

📖 getline() lê a linha inteira

string frase;
getline(cin, frase);
cout << frase;

getline() lê até a quebra de linha e preserva os espaços internos.

Entrada

Paulo Rettore

Leitura

getline()

Resultado

nome completo

⚠️ O problema do \n no buffer

int idade;
string nome;

cin >> idade;
getline(cin, nome); // pode ler vazio

Depois de cin >>, a quebra de linha pode permanecer no buffer. O getline() encontra essa quebra imediatamente.

🛠️ A correção com cin.ignore()

#include <limits>

int idade;
string nome;

cin >> idade;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
getline(cin, nome);

Descartamos tudo até o fim da linha antes de ler o nome completo. Para uma entrada simples, cin.ignore() também pode ser suficiente.

🧩 Leitura com separadores

O terceiro argumento de getline() define o delimitador. A leitura termina no separador, que é consumido e não entra no texto.

string nome, cidade;

// Entrada: Ana Silva;Lavras
getline(cin, nome, ';');
getline(cin, cidade);       // até o fim da linha

cout << nome << " mora em " << cidade;

A mesma ideia funciona com cin, ifstream e stringstream. Use o delimitador que o arquivo realmente utiliza: ';', ',' ou outro.

📄 O arquivo CSV: formato real

Antes do código, observe o arquivo badassComputerPeople.csv usado nesta aula.

#nome,sexo,pais,ano de nascimento,ano de falecimento,descrição
10,,,,,
Ada Lovelace,F,Inglaterra,1815,1852,É considerada a primeira programadora de computador, a liguagem Ada foi nomeada em sua homenagem
Charles Babbage,M,Inglaterra,1791,1871,Projetou a máquina analítica, um modelo de computador
Alan Turing,M,Inglaterra,1912,1954,Um dos maiores teóricos da computação, criou a máquina de Turing, modelo teórico de um computador. Também é autor do Teste de Turing, para avaliar se uma IA pode se passar por um ser humano
John von Neuman,M,Hungria,1903,1957,Proponente da arquitetura de von Neuman, que é a base dos computadores modernos
Blaise Pascal,M,França,1623,1662,Inventor da calculadora mecânica, a linguagem Pascal foi nomeada em sua homenagem
Hedy Lamar,F,Áustria,1914,2000,Atriz, inventou, com o compositor George Antheil, um sistema de comunicações para as Forças Armadas dos Estados Unidos que serviu de base para a atual telefonia celular
George Antheil,M,EUA,1900,1959,Compositor, inventou, com a atriz Hedy Lamar, um sistema de comunicações para as Forças Armadas dos Estados Unidos que serviu de base para a atual telefonia celular
Noam Chomsky,M,EUA,1928,0,Fez diversas contribuições para a computação com seu trabalho em Linguística
Margaret Hamilton,F,EUA,1936,0,Criadora do termo 'Engenharia de Software', desenvolveu o conceito de software assíncrono
Bjarne Stroustrup,M,Dinamarca,1950,0,Criador do C++, odiado por vários alunos da UFLA

1. Cabeçalho

Nomeia os seis campos da tabela.

2. Quantidade

10 informa quantos registros serão lidos.

3. Registros

Depois vêm as dez pessoas, uma por linha.

O arquivo tem 12 linhas: cabeçalho, quantidade de registros e 10 registros de pessoas. A descrição é o último campo e pode conter vírgulas.

🔄 Leitura direta: preparação

O programa lê diretamente do ifstream. Primeiro, descarta o cabeçalho e lê a quantidade de registros.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main() {
    string linha;
    int numRegistros;
    ifstream arquivo_csv("badassComputerPeople.csv");

    if (not(arquivo_csv)) {
        cout << "Erro: não foi possível abrir o arquivo!" << endl;
    } else {
        getline(arquivo_csv, linha); // cabeçalho
        arquivo_csv >> numRegistros;
        getline(arquivo_csv, linha); // resto da linha
        // agora o fluxo está pronto para os registros
    }
    return 0;
}

Depois de >> numRegistros, o segundo getline() consome a quebra de linha que ficou pendente.

🔄 Leitura direta: campos e saída

Dentro do laço, cada operador lê exatamente o próximo campo do registro.

for (int i = 0; i < numRegistros; i++) {
    string nome, pais, descricao;
    char sexo, lixo;
    short anoNascimento, anoFalecimento;

    getline(arquivo_csv, nome, ',');
    arquivo_csv >> sexo;
    arquivo_csv >> lixo; // descarta a vírgula
    getline(arquivo_csv, pais, ',');
    arquivo_csv >> anoNascimento >> lixo;
    arquivo_csv >> anoFalecimento >> lixo;

    if (arquivo_csv.peek() == '"') {
        arquivo_csv.get(lixo); // abre-aspas
        getline(arquivo_csv, descricao, '"');
        getline(arquivo_csv, linha); // fim da linha
    } else {
        getline(arquivo_csv, descricao);
    }

    cout << "BCP #" << i + 1 << ":" << endl
         << nome << endl << sexo << endl
         << pais << endl
         << anoNascimento << "-" << anoFalecimento << endl
         << descricao << endl << endl;
}

peek() observa o próximo caractere sem removê-lo. Assim o código decide se a descrição começa entre aspas ou não.

🧭 Leitura direta: o que acontece?

Texto

getline(arquivo, nome, ',') lê até a próxima vírgula e preserva espaços.

Número

arquivo >> anoNascimento converte a sequência para o tipo numérico.

Separador

arquivo >> lixo remove a vírgula que ficou no fluxo.

Ada Lovelace,F,Inglaterra,1815,1852,É considerada a primeira programadora, ...

nome      = "Ada Lovelace"
sexo      = 'F'
pais      = "Inglaterra"
anoNasc.  = 1815
anoFalec. = 1852
descricao = "É considerada a primeira programadora, ..."

A descrição é lida por último até o fim da linha. Por isso, as vírgulas dentro dela não deslocam os campos anteriores.

⚠️ Limites da leitura direta

  • O programa depende da ordem exata dos campos.
  • Um campo ausente ou uma vírgula inesperada nos campos iniciais pode deslocar as leituras seguintes.
  • O código trata a descrição como o restante da linha; ele não é um analisador completo de todas as regras de CSV.
  • A variável lixo descarta caracteres específicos; ela não valida se o separador realmente era uma vírgula.

Escolha da técnica: use a leitura direta para arquivos simples e conhecidos. Depois veremos stringstream para separar uma linha já carregada e converter campos com mais flexibilidade.

📦 Agora: o que são <sstream> e stringstream?

#include <sstream>

Inclui as classes que tratam uma string como um fluxo de entrada e saída, usando a memória do programa.

stringstream

É um objeto que recebe uma linha já lida e permite extrair seus campos aos poucos, usando >> ou getline().

#include <sstream>

std::string linha = "Ada Lovelace,F,Inglaterra,1815,1852,Descrição";
std::stringstream campos(linha);

stringstream não abre arquivo e não lê diretamente do teclado: ele organiza uma string que já está na memória.

🧪 stringstream: separar uma linha

Podemos carregar uma linha inteira e depois extrair os campos. No arquivo desta aula, o último campo é lido sem delimitador para preservar suas vírgulas.

string linha = "Ada Lovelace,F,Inglaterra,1815,1852,Descrição";
stringstream campos(linha);
string nome, pais, descricao;
char sexo;
short anoNascimento, anoFalecimento;

getline(campos, nome, ',');
campos >> sexo >> lixo;
getline(campos, pais, ',');
campos >> anoNascimento >> lixo;
campos >> anoFalecimento >> lixo;
getline(campos, descricao); // restante da linha

Cada leitura avança o cursor de campos. O último getline() captura o restante, inclusive vírgulas da descrição.

📚 Ler o arquivo com stringstream

#include <fstream>
#include <sstream>

ifstream arquivo("badassComputerPeople.csv");
string linha;
int numRegistros;

getline(arquivo, linha); // cabeçalho
arquivo >> numRegistros;
getline(arquivo, linha); // resto da linha

for (int i = 0; i < numRegistros; i++) {
    getline(arquivo, linha);
    stringstream campos(linha);
    string nome, pais, descricao;
    char sexo, lixo;
    short nascimento, falecimento;

    getline(campos, nome, ',');
    campos >> sexo >> lixo;
    getline(campos, pais, ',');
    campos >> nascimento >> lixo;
    campos >> falecimento >> lixo;
    getline(campos, descricao);
}

Comparação: a leitura direta trabalha no arquivo enquanto avança; com stringstream, primeiro lemos a linha e depois processamos uma cópia dela em memória.

🧭 Cuidados com CSV

  • Confirme se o arquivo abriu antes de ler.
  • Identifique se o separador é ; ou ,.
  • Decida se a primeira linha é um cabeçalho e descarte-a quando necessário.
  • Verifique se todos os campos esperados foram encontrados antes de converter.
  • Use getline() para preservar espaços em nomes e descrições.

Um CSV não é necessariamente separado por vírgulas: no Brasil, o ponto e vírgula é comum quando a vírgula aparece em números decimais.

🔎 Percorrer uma string

string palavra = "algoritmo";
int vogais = 0;

for (int i = 0; i < palavra.size(); i++) {
    char c = palavra[i];
    if (c == 'a' or c == 'e' or c == 'i' or
        c == 'o' or c == 'u')
        vogais++;
}

Uma string pode ser percorrida como uma sequência de caracteres. O índice inicial é 0 e o último índice é size() - 1.

🧩 Desafio: cadastro simples

Leia a idade e o nome completo de uma pessoa. Depois, mostre uma mensagem de apresentação.

  1. Leia a idade com cin.
  2. Use cin.ignore() quando necessário.
  3. Leia o nome completo com getline().

Amplie o desafio: leia também cidade e curso em uma linha separada por ;.

🧩 Prática em aula

Leia uma linha no formato nome;cidade;curso e mostre cada campo em uma linha diferente.

Entrada: Maria Silva;Lavras;Engenharia

Saída esperada:
Nome: Maria Silva
Cidade: Lavras
Curso: Engenharia

Gabarito orientador: use getline(cin, campo, ';') para os dois primeiros campos e um getline(cin, campo) para o último.

📚 Referências e materiais

Use estas fontes para consultas pontuais depois da aula:

Os slides completos, o Campus Virtual e o DREDD continuam sendo as fontes principais da disciplina.

📌 Resumo da aula

  • string armazena textos e possui length(), size(), find(), erase() e replace().
  • std::string::npos indica que uma busca não encontrou o trecho procurado.
  • cin lê uma palavra; getline() lê uma linha inteira ou um campo até um separador.
  • Após cin >>, descarte a quebra de linha quando necessário.
  • #include <sstream> disponibiliza o stringstream para separar e converter textos em memória.
  • Para CSV, combine ifstream, getline() e stringstream.

PRÓXIMA AULA

⏭️ Próxima aula

Ponteiros, alocação dinâmica, busca binária e recursão

Prof. Paulo Rettore

GAC124 — Introdução aos Algoritmos