Bloco 4 – Estruturas e Strings
Este bloco aborda estruturas (structs) e manipulação de strings em C++.
Resumo do Conteúdo
Estruturas permitem agrupar dados relacionados em um único tipo composto. Strings são essenciais para processar texto. Este bloco ensina como criar e manipular estruturas complexas, trabalhar com vetores de estruturas e dominar operações com strings da STL. Compreender esses conceitos é fundamental para organizar dados e processar informações textuais de forma eficiente.
Declarar e definir estruturas
Declaração Básica de Estrutura
// Declaração de estrutura
struct Pessoa {
string nome;
int idade;
double altura;
};
Explicação:
structdefine um tipo de dados composto- Agrupa múltiplos dados relacionados (membros)
- Cada membro pode ter tipo diferente
- Termina com
;após a chave
Definição e Inicialização de Estrutura
// Definir estrutura
struct Ponto {
int x;
int y;
};
// Criar instância
Ponto p1;
p1.x = 10;
p1.y = 20;
// Criar com inicialização direta
Ponto p2 = {5, 15};
// C++11 uniform initialization
Ponto p3{30, 40};
// Inicialização com valores padrão (C++11)
Ponto p4 = {}; // x=0, y=0
Formas de inicialização:
struct Retangulo {
double largura;
double altura;
};
// 1. Atribuição membro a membro
Retangulo r1;
r1.largura = 10.0;
r1.altura = 5.0;
// 2. Lista de inicialização
Retangulo r2 = {10.0, 5.0};
// 3. Uniform initialization (C++11)
Retangulo r3{10.0, 5.0};
// 4. Designated initializers (C++20)
Retangulo r4 = {.largura = 10.0, .altura = 5.0};
Estruturas Aninhadas
struct Endereco {
string rua;
string cidade;
int cep;
};
struct Funcionario {
string nome;
int id;
Endereco endereco; // Estrutura dentro de estrutura
};
// Uso
Funcionario func;
func.nome = "João Silva";
func.id = 12345;
func.endereco.rua = "Rua das Flores, 123";
func.endereco.cidade = "São Paulo";
func.endereco.cep = 12345678;
// Ou com inicialização
Funcionario func2 = {
"Maria Santos",
67890,
{"Av. Paulista, 1000", "São Paulo", 01310100}
};
Explicação: Estruturas podem conter outras estruturas, permitindo modelar dados hierárquicos complexos.
Estrutura com Funções-Membro
struct Retangulo {
double largura;
double altura;
// Função-membro (método)
double area() {
return largura * altura;
}
double perimetro() {
return 2 * (largura + altura);
}
// Função para verificar se é quadrado
bool ehQuadrado() {
return largura == altura;
}
};
// Uso
Retangulo ret;
ret.largura = 5.0;
ret.altura = 3.0;
cout << "Área: " << ret.area() << endl; // 15.0
cout << "Perímetro: " << ret.perimetro() << endl; // 16.0
cout << "É quadrado? " << (ret.ehQuadrado() ? "Sim" : "Não") << endl;
Estrutura vs Classe:
- Em C++,
structeclasssão quase idênticos - Diferença:
structtem membros públicos por padrão,classprivados - Use
structpara simples agrupamento de dados - Use
classpara objetos com comportamento complexo
Construtor em Estrutura (C++11)
struct Ponto {
int x, y;
// Construtor
Ponto(int x_val, int y_val) : x(x_val), y(y_val) {}
// Construtor padrão
Ponto() : x(0), y(0) {}
};
// Uso
Ponto p1(10, 20); // Usa construtor parametrizado
Ponto p2; // Usa construtor padrão (0, 0)
Acessar membros da estrutura usando o operador ponto (.)
Acesso Básico a Membros
struct Aluno {
string nome;
int matricula;
double media;
};
int main() {
Aluno aluno;
// Atribuir valores usando operador ponto
aluno.nome = "Carlos Silva";
aluno.matricula = 202301;
aluno.media = 8.5;
// Acessar valores usando operador ponto
cout << "Nome: " << aluno.nome << endl;
cout << "Matrícula: " << aluno.matricula << endl;
cout << "Média: " << aluno.media << endl;
return 0;
}
Explicação: O operador . (ponto) acessa membros de uma estrutura através de uma instância da estrutura.
Ponteiro para Estrutura
struct Livro {
string titulo;
string autor;
int paginas;
};
int main() {
Livro livro;
Livro* ptr = &livro;
// Acesso usando operador ponto (objeto)
livro.titulo = "C++ Programming";
// Acesso usando operador seta (ponteiro)
ptr->autor = "Bjarne Stroustrup";
ptr->paginas = 1000;
// Alternativa: desreferenciar depois usar ponto
(*ptr).titulo = "The C++ Programming Language";
cout << livro.titulo << endl;
cout << livro.autor << endl;
cout << livro.paginas << endl;
return 0;
}
Operadores de acesso:
.(ponto): Para objetos->(seta): Para ponteiros (equivalente a(*ptr).membro)
Modificar Membros da Estrutura
struct Carro {
string marca;
string modelo;
int ano;
double preco;
};
void atualizarPreco(Carro& carro, double novoPreco) {
carro.preco = novoPreco;
}
void aplicarDesconto(Carro& carro, double percentual) {
carro.preco *= (1.0 - percentual / 100.0);
}
int main() {
Carro meuCarro;
meuCarro.marca = "Toyota";
meuCarro.modelo = "Corolla";
meuCarro.ano = 2023;
meuCarro.preco = 95000.0;
// Atualizar preço
atualizarPreco(meuCarro, 98000.0);
// Aplicar desconto de 10%
aplicarDesconto(meuCarro, 10);
cout << "Preço final: R$ " << fixed << setprecision(2)
<< meuCarro.preco << endl; // R$ 88200.00
return 0;
}
Comparar Estruturas
struct Data {
int dia, mes, ano;
// Função para comparar datas
bool ehAntesDe(const Data& outra) const {
if (ano != outra.ano) return ano < outra.ano;
if (mes != outra.mes) return mes < outra.mes;
return dia < outra.dia;
}
bool ehIgual(const Data& outra) const {
return dia == outra.dia && mes == outra.mes && ano == outra.ano;
}
};
int main() {
Data d1 = {15, 3, 2024};
Data d2 = {20, 3, 2024};
if (d1.ehAntesDe(d2)) {
cout << "d1 é anterior a d2" << endl;
}
return 0;
}
Nota: C++ não compara estruturas automaticamente com ==. Você precisa implementar a comparação.
Declarar vetores de estruturas e acessar seus campos
Vector de Estruturas
#include <vector>
using namespace std;
struct Produto {
string nome;
double preco;
int quantidade;
};
int main() {
// Declarar vector de estruturas
vector<Produto> estoque;
// Adicionar produtos
Produto p1 = {"Notebook", 2500.00, 5};
Produto p2 = {"Mouse", 35.00, 20};
Produto p3 = {"Teclado", 150.00, 15};
estoque.push_back(p1);
estoque.push_back(p2);
estoque.push_back(p3);
// Acessar campos
for (int i = 0; i < estoque.size(); i++) {
cout << "Produto: " << estoque[i].nome << endl;
cout << "Preço: R$ " << fixed << setprecision(2)
<< estoque[i].preco << endl;
cout << "Quantidade: " << estoque[i].quantidade << endl;
cout << "---" << endl;
}
return 0;
}
Explicação: Vector de estruturas funciona como vector de qualquer tipo, mas cada elemento é uma estrutura com múltiplos campos.
Inicializar Vector de Estruturas
struct Coordenada {
int x;
int y;
};
int main() {
// Inicializar com lista (C++11)
vector<Coordenada> pontos = {
{0, 0},
{10, 20},
{30, 40},
{50, 60}
};
// Acessar usando range-based for
for (const Coordenada& p : pontos) {
cout << "(" << p.x << ", " << p.y << ")" << endl;
}
// Adicionar novos pontos
pontos.push_back({70, 80});
pontos.push_back({90, 100});
return 0;
}
Modificar Elementos do Vector
struct Estudante {
string nome;
double nota;
};
int main() {
vector<Estudante> turma = {
{"Alice", 8.5},
{"Bob", 7.0},
{"Carlos", 6.5}
};
// Modificar nota específica
turma[1].nota = 8.5;
// Adicionar novo estudante
Estudante novo = {"Diana", 9.0};
turma.push_back(novo);
// Modificar através de referência
for (Estudante& e : turma) {
e.nota += 0.5; // Bônus de 0.5 para todos
}
// Exibir todos
for (const Estudante& e : turma) {
cout << e.nome << ": " << e.nota << endl;
}
return 0;
}
Ordenar Vector de Estruturas
#include <algorithm>
#include <vector>
using namespace std;
struct Funcionario {
string nome;
double salario;
};
// Função de comparação
bool compararPorSalario(const Funcionario& a, const Funcionario& b) {
return a.salario > b.salario; // Ordem decrescente
}
int main() {
vector<Funcionario> funcionarios = {
{"Alice", 5000.00},
{"Bob", 7000.00},
{"Carlos", 4500.00},
{"Diana", 6000.00}
};
// Ordenar por salário (decrescente)
sort(funcionarios.begin(), funcionarios.end(), compararPorSalario);
// Exibir lista ordenada
cout << "Funcionários por salário:" << endl;
for (const Funcionario& f : funcionarios) {
cout << f.nome << ": R$ " << fixed << setprecision(2)
<< f.salario << endl;
}
return 0;
}
Usando lambda (C++11):
// Ordenar por nome (ordem alfabética)
sort(funcionarios.begin(), funcionarios.end(),
[](const Funcionario& a, const Funcionario& b) {
return a.nome < b.nome;
});
Buscar em Vector de Estruturas
struct Item {
int id;
string descricao;
};
int main() {
vector<Item> items = {
{101, "Produto A"},
{202, "Produto B"},
{303, "Produto C"}
};
int idBusca = 202;
bool encontrado = false;
// Busca linear
for (const Item& item : items) {
if (item.id == idBusca) {
cout << "Encontrado: " << item.descricao << endl;
encontrado = true;
break;
}
}
if (!encontrado) {
cout << "Item não encontrado" << endl;
}
return 0;
}
Estatísticas com Vector de Estruturas
struct Venda {
string produto;
double valor;
int quantidade;
};
int main() {
vector<Venda> vendas = {
{"Notebook", 2500.00, 2},
{"Mouse", 35.00, 10},
{"Teclado", 150.00, 5}
};
// Calcular total de vendas
double total = 0.0;
int totalItens = 0;
for (const Venda& v : vendas) {
double subtotal = v.valor * v.quantidade;
total += subtotal;
totalItens += v.quantidade;
cout << v.produto << ": R$ " << subtotal << endl;
}
cout << "\nTotal: R$ " << fixed << setprecision(2) << total << endl;
cout << "Total de itens: " << totalItens << endl;
cout << "Média por item: R$ " << (total / totalItens) << endl;
return 0;
}
Declarar, inicializar e manipular objetos std::string
Declaração e Inicialização de Strings
#include <string>
using namespace std;
// String vazia
string str1;
// Inicializar com literal
string str2 = "Olá";
// Inicializar com outra string
string str3 = str2;
// Inicializar com caractere repetido
string str4(5, 'A'); // "AAAAA"
// Uniform initialization (C++11)
string str5{"Mundo"};
// Parte de outra string
string str6 = "Hello World";
string str7(str6, 6, 5); // "World" (a partir da posição 6, 5 caracteres)
Explicação: std::string é uma classe da biblioteca padrão que gerencia automaticamente a memória para strings.
Entrada e Saída de Strings
#include <iostream>
#include <string>
using namespace std;
int main() {
string nome;
// Ler palavra (até espaço ou Enter)
cout << "Digite seu nome: ";
cin >> nome;
// Ler linha completa (com espaços)
string nomeCompleto;
cout << "Digite nome completo: ";
cin.ignore(); // Limpar buffer
getline(cin, nomeCompleto);
// Saída
cout << "Nome: " << nome << endl;
cout << "Nome completo: " << nomeCompleto << endl;
return 0;
}
Diferença:
cin >>lê até espaço/tab/Entergetline()lê linha completa incluindo espaços
Concatenação de Strings
string primeiro = "Olá";
string segundo = "Mundo";
// Usando operador +
string resultado1 = primeiro + " " + segundo; // "Olá Mundo"
// Usando operador +=
string resultado2 = primeiro;
resultado2 += " ";
resultado2 += segundo; // "Olá Mundo"
// Usando método append()
string resultado3 = primeiro;
resultado3.append(" ");
resultado3.append(segundo); // "Olá Mundo"
// Concatenar com literal
string saudacao = "Olá, " + string("mundo") + "!";
cout << resultado1 << endl;
Cuidado: Não pode concatenar dois literais diretamente:
// string str = "Hello" + " World"; // ERRO!
string str = string("Hello") + " World"; // OK
string str2 = "Hello" + string(" World"); // OK
Tamanho e Acesso
string texto = "C++ Programming";
// Obter tamanho
int tamanho1 = texto.length(); // 15
int tamanho2 = texto.size(); // 15 (mesmo que length)
// Verificar se vazia
bool vazia = texto.empty(); // false
// Acessar caracteres
char primeiro = texto[0]; // 'C' (sem verificação)
char segundo = texto.at(1); // '+' (com verificação de limites)
// Modificar caractere
texto[0] = 'c'; // "c++ Programming"
// Último caractere
char ultimo = texto[texto.length() - 1]; // 'g'
char ultimo2 = texto.back(); // 'g' (C++11)
// Primeiro caractere
char primeiro2 = texto.front(); // 'c' (C++11)
Iterar através da string:
string texto = "Hello";
// Índice tradicional
for (int i = 0; i < texto.length(); i++) {
cout << texto[i] << " ";
}
cout << endl;
// Range-based for
for (char c : texto) {
cout << c << " ";
}
cout << endl;
// Modificar com referência
for (char& c : texto) {
c = toupper(c); // Converte para maiúscula
}
cout << texto << endl; // "HELLO"
Métodos de Manipulação de String
string texto = "Hello World";
// Substring
string sub1 = texto.substr(0, 5); // "Hello" (posição 0, 5 caracteres)
string sub2 = texto.substr(6); // "World" (do 6 até o final)
// Buscar
size_t pos1 = texto.find("World"); // 6 (posição onde começa)
size_t pos2 = texto.find("xyz"); // string::npos (não encontrado)
// Buscar do final
size_t pos3 = texto.rfind("o"); // 7 (último 'o')
// Buscar qualquer caractere de um conjunto
size_t pos4 = texto.find_first_of("aeiou"); // 1 ('e')
size_t pos5 = texto.find_last_of("aeiou"); // 7 ('o')
// Substituir
texto.replace(0, 5, "Hi"); // "Hi World" (substitui "Hello")
// Inserir
texto.insert(2, " there"); // "Hi there World"
// Apagar
texto.erase(0, 3); // "there World" (remove 3 caracteres)
// Limpar completamente
texto.clear(); // ""
// Verificar se vazia
bool vazia = texto.empty(); // true
Conversões de Tipo
#include <string>
using namespace std;
// String para número
string numStr = "123";
int num = stoi(numStr); // 123 (string to int)
long lng = stol("1000000"); // 1000000 (string to long)
float flt = stof("3.14"); // 3.14 (string to float)
double dbl = stod("3.14159"); // 3.14159 (string to double)
// Número para string
int valor = 42;
string str1 = to_string(valor); // "42"
double pi = 3.14159;
string str2 = to_string(pi); // "3.141590"
// String C-style
string cplusplus = "Hello";
const char* cstring = cplusplus.c_str(); // Ponteiro para array C
Realizar operações básicas e comparações com strings
Comparação de Strings
string str1 = "maçã";
string str2 = "banana";
string str3 = "maçã";
// Usando operadores de comparação
bool igual = (str1 == str3); // true
bool diferente = (str1 != str2); // true
bool menor = (str1 < str2); // false (ordem alfabética)
bool maior = (str2 > str1); // true
bool menorIgual = (str1 <= str3); // true
bool maiorIgual = (str2 >= str1); // true
// Usando método compare()
int result1 = str1.compare(str2); // negativo (str1 < str2)
int result2 = str1.compare(str3); // 0 (iguais)
int result3 = str2.compare(str1); // positivo (str2 > str1)
// Comparação case-insensitive (necessita loop manual)
bool igualIgnoraCase(const string& a, const string& b) {
if (a.length() != b.length()) return false;
for (size_t i = 0; i < a.length(); i++) {
if (tolower(a[i]) != tolower(b[i])) return false;
}
return true;
}
Explicação da comparação lexicográfica:
"apple" < "banana" // true (ordem alfabética)
"10" < "2" // true (comparação de strings, não números!)
"A" < "a" // true (maiúsculas vêm antes na tabela ASCII)
Conversão de Caso (Maiúsculas/Minúsculas)
#include <algorithm>
#include <cctype>
using namespace std;
string texto = "Hello World";
// Converter para maiúsculas
transform(texto.begin(), texto.end(), texto.begin(), ::toupper);
cout << texto << endl; // "HELLO WORLD"
// Converter para minúsculas
transform(texto.begin(), texto.end(), texto.begin(), ::tolower);
cout << texto << endl; // "hello world"
// Capitalizar primeira letra
string palavra = "hello";
palavra[0] = toupper(palavra[0]);
cout << palavra << endl; // "Hello"
// Capitalizar cada palavra
string frase = "hello world from cpp";
bool novapalavra = true;
for (char& c : frase) {
if (isspace(c)) {
novapalavra = true;
} else if (novapalavra) {
c = toupper(c);
novapalavra = false;
}
}
cout << frase << endl; // "Hello World From Cpp"
Busca em Strings
string texto = "The quick brown fox jumps over the lazy dog";
// Encontrar primeira ocorrência
size_t pos1 = texto.find("fox"); // 16
if (pos1 != string::npos) {
cout << "Encontrado na posição " << pos1 << endl;
}
// Encontrar a partir de uma posição
size_t pos2 = texto.find("the", 10); // 31 (segunda ocorrência)
// Encontrar última ocorrência
size_t pos3 = texto.rfind("o"); // 41 (último 'o')
// Encontrar primeiro de um conjunto
size_t pos4 = texto.find_first_of("aeiou"); // 2 ('e')
// Encontrar primeiro que NÃO seja do conjunto
size_t pos5 = texto.find_first_not_of("The "); // 4 ('q')
// Contar ocorrências
string busca = "o";
int contador = 0;
size_t pos = texto.find(busca);
while (pos != string::npos) {
contador++;
pos = texto.find(busca, pos + 1);
}
cout << "Ocorrências de 'o': " << contador << endl; // 4
Modificação de Strings
string texto = " Hello World ";
// Remover espaços iniciais e finais (trim)
texto.erase(0, texto.find_first_not_of(" ")); // Remove início
texto.erase(texto.find_last_not_of(" ") + 1); // Remove final
cout << "|" << texto << "|" << endl; // "|Hello World|"
// Reverter string
string original = "Hello";
reverse(original.begin(), original.end());
cout << original << endl; // "olleH"
// Substituir todas as ocorrências
string frase = "Eu gosto de gatos. Gatos são fofos.";
string de = "gatos";
string para = "cães";
size_t pos = 0;
while ((pos = frase.find(de, pos)) != string::npos) {
frase.replace(pos, de.length(), para);
pos += para.length();
}
cout << frase << endl; // "Eu gosto de cães. Gatos são fofos."
// (Note que é case-sensitive, "Gatos" com G maiúsculo não foi alterado)
Dividir String (Split)
#include <sstream>
#include <vector>
// Dividir string por delimitador
vector<string> split(const string& texto, char delimitador) {
vector<string> resultado;
stringstream ss(texto);
string item;
while (getline(ss, item, delimitador)) {
resultado.push_back(item);
}
return resultado;
}
int main() {
string csv = "João,25,Engenheiro";
vector<string> partes = split(csv, ',');
for (const string& parte : partes) {
cout << parte << endl;
}
// João
// 25
// Engenheiro
return 0;
}
Juntar Strings (Join)
#include <vector>
#include <string>
string join(const vector<string>& partes, const string& separador) {
string resultado;
for (size_t i = 0; i < partes.size(); i++) {
resultado += partes[i];
if (i < partes.size() - 1) {
resultado += separador;
}
}
return resultado;
}
int main() {
vector<string> palavras = {"C++", "é", "poderoso"};
string frase = join(palavras, " ");
cout << frase << endl; // "C++ é poderoso"
return 0;
}
Validação de Strings
#include <cctype>
// Verificar se é número
bool ehNumero(const string& str) {
for (char c : str) {
if (!isdigit(c)) return false;
}
return !str.empty();
}
// Verificar se é letra
bool ehAlfabetico(const string& str) {
for (char c : str) {
if (!isalpha(c)) return false;
}
return !str.empty();
}
// Verificar se é alfanumérico
bool ehAlfanumerico(const string& str) {
for (char c : str) {
if (!isalnum(c)) return false;
}
return !str.empty();
}
int main() {
cout << ehNumero("12345") << endl; // 1 (true)
cout << ehNumero("123a5") << endl; // 0 (false)
cout << ehAlfabetico("Hello") << endl; // 1 (true)
cout << ehAlfabetico("Hello!") << endl; // 0 (false)
return 0;
}
Exemplo Completo: Processamento de Texto
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string frase = "The Quick Brown Fox";
// 1. Converter para minúsculas
transform(frase.begin(), frase.end(), frase.begin(), ::tolower);
cout << "Minúsculas: " << frase << endl;
// 2. Contar palavras
int palavras = 1;
for (char c : frase) {
if (c == ' ') palavras++;
}
cout << "Número de palavras: " << palavras << endl;
// 3. Buscar palavra específica
size_t pos = frase.find("fox");
if (pos != string::npos) {
cout << "'fox' encontrado na posição " << pos << endl;
}
// 4. Contar vogais
int vogais = 0;
for (char c : frase) {
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
vogais++;
}
}
cout << "Número de vogais: " << vogais << endl;
// 5. Reverter
reverse(frase.begin(), frase.end());
cout << "Reverso: " << frase << endl;
return 0;
}
Saída:
Minúsculas: the quick brown fox
Número de palavras: 4
'fox' encontrado na posição 16
Número de vogais: 5
Reverso: xof nworb kciuq eht
Resumo dos Pontos-Chave
- Estruturas: Agrupam dados relacionados em um tipo composto
- Operador
.: Acessa membros de estrutura (objeto) - Operador
->: Acessa membros de estrutura (ponteiro) - Vector de Structs: Coleção dinâmica de estruturas, útil para listas de dados
- std::string: Classe para manipulação de texto com gerenciamento automático
- Concatenação:
+,+=,append()juntam strings - Comparação: Operadores relacionais comparam lexicograficamente
- Busca:
find(),rfind(),findfirstof()localizam substrings - Manipulação:
substr(),replace(),insert(),erase()modificam strings - Conversão:
to_string(),stoi(),stod()convertem entre tipos
Dicas Importantes:
- Use
structpara simples agrupamento de dados - Sempre verifique
string::nposem operações de busca - Strings C++ gerenciam memória automaticamente (sem delete necessário)
- Use
const string&em parâmetros para evitar cópias desnecessárias std::stringé preferível a arrays de char (C-strings)