Projeto Agenda de Contatos
A Ana quer guardar os contatos dos clientes da lojinha: nome, telefone e e-mail. Neste projeto você vai construir uma agenda de terminal com um menu para adicionar, listar, buscar e remover contatos, e que guarda tudo num arquivo: ao abrir o programa no dia seguinte, os contatos continuam lá. É o primeiro projeto do guia com dados que sobrevivem ao fim do programa.
- Criar um tipo próprio com struct.
- Guardar vários contatos num std::vector:
push_back,size,erase. - Montar um menu com while e switch.
- Ler linhas inteiras com getline, e o problema de misturá-lo com
cin >>. - Comparar textos sem diferenciar maiúsculas e minúsculas (funções de string,
tolower). - Gravar e ler um arquivo de texto com fstream.
O que vamos construir
A agenda pronta, aberta pela segunda vez na máquina da Ana (os contatos vieram do arquivo gravado na primeira vez). Depois de "Opção:" e das outras perguntas está o que ela digitou:
$ ./agenda === Agenda da Ana === Carregados 2 contatos de agenda.txt. 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 1 Nome: Carla Dias Telefone: (31) 90000-0003 E-mail: carla@exemplo.com Contato adicionado: Carla Dias 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 3 Buscar por: LI 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 0 Agenda salva em agenda.txt (3 contatos). Até logo! $ cat agenda.txt Ana Souza;(11) 90000-0001;ana@exemplo.com Bruno Lima;(21) 90000-0002;bruno@exemplo.com Carla Dias;(31) 90000-0003;carla@exemplo.com
Os telefones e e-mails são de mentira (exemplo.com é um domínio reservado para exemplos). Seis etapas até lá:
- O contato e a lista (
struct,vector). - O menu e o "adicionar" (
while,switch,getlineestd::ws). - Buscar sem diferenciar maiúsculas (
tolower,contains). - Remover (
erasee validação do número). - Salvar no arquivo (
std::ofstream). - Carregar do arquivo (
std::ifstream,istringstream).
Antes de começar
Este projeto usa o Nível 1 inteiro e um pouco do Nível 2. Você precisa ter visto Structs, std::vector, Funções, Por Valor × Por Referência e getline; a aula Ler e Escrever Arquivos ajuda nas etapas 5 e 6. Fazer antes a Calculadora também ajuda: a validação da entrada é parecida.
$ mkdir -p cpp/agenda $ cd cpp/agenda
Etapa 1 · O contato e a lista
Um contato tem três informações: nome, telefone e e-mail. Poderíamos usar três variáveis soltas, mas com 50 contatos seriam 150 variáveis. Em vez disso, criamos um tipo novo, Contato, que junta as três (veja Structs). E para guardar vários contatos, um std::vector<Contato>: uma lista que cresce.
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
listar(agenda);
}
- struct Contato { … };
- Define o tipo
Contato, com três camposstd::string. Repare no;depois da chave: ele é obrigatório no fim de umastruct. - void mostrar(std::size_t numero, const Contato& c)
- Mostra um contato numa linha, com o número dele na frente. O contato é recebido por
const&: sem cópia, sem poder mudar (veja Boas Práticas).std::size_té o tipo dos tamanhos e posições de umvector(um inteiro sem sinal). - c.nome
- O ponto acessa um campo do contato: "o nome de
c". - agenda.empty()
truese a lista estiver vazia. Nesse caso, avisamos e saímos comreturn;.- for (std::size_t i = 0; i < agenda.size(); ++i)
- Percorre a lista pela posição. Aqui o for com índice é melhor que o range-for, porque precisamos do número de cada contato. O
iéstd::size_t, do mesmo tipo desize(): assim não há o aviso de "sinais diferentes". - mostrar(i + 1, agenda[i])
- As posições do
vectorcomeçam em 0, mas pessoas contam a partir de 1. Por isso mostramosi + 1. - std::vector<Contato> agenda{ {…}, {…}, };
- Cria a lista já com dois contatos. Cada
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"}preenche os campos na ordem em que foram declarados nastruct.
$ g++ -std=c++23 -Wall -Wextra agenda.cpp -o agenda $ ./agenda === Agenda da Ana === --- Contatos (2) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com
Missão (etapa 1): acrescente um terceiro contato à lista inicial: Carla Dias, telefone (31) 90000-0003, e-mail carla@exemplo.com. A listagem deve mostrar --- Contatos (3) ---.
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
listar(agenda);
}
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
{"Carla Dias", "(31) 90000-0003", "carla@exemplo.com"},
};
listar(agenda);
}
Etapa 2 · O menu e o "adicionar"
Agora a agenda vira um programa interativo: um menu que se repete até a pessoa escolher 0. Cada opção chama uma função. Nesta etapa, o menu tem "Adicionar", "Listar" e "Sair". Estas são as partes novas (as funções mostrar e listar e a struct não mudam):
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 0: break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
| Parte | O que faz |
|---|---|
ler_opcao() | Lê o número da opção. Se a pessoa digitar texto, limpa o erro do cin e devolve -1 ("opção inválida"). Se a entrada acabar (Ctrl+D), devolve 0, como se ela tivesse escolhido sair. É a mesma técnica da etapa 5 da Calculadora. |
void adicionar(std::vector<Contato>& agenda) | Recebe a agenda por referência (&, sem const): a função precisa mudar a lista original, acrescentando um contato. Sem o &, ela acrescentaria numa cópia, que sumiria no fim da função. |
Contato novo; | Um contato vazio, preenchido campo por campo. |
std::getline(std::cin >> std::ws, novo.nome); | Lê a linha inteira, com espaços. O >> sozinho pararia no primeiro espaço e leria só "Carla". O std::ws é explicado logo abaixo. |
agenda.push_back(novo); | Acrescenta o contato no fim da lista. |
int opcao = -1; while (opcao != 0) | O laço do menu: repete até a opção ser 0. Começa com -1 para entrar no laço na primeira vez. |
case 0: break; | Nada a fazer: o while vê o 0 e termina. Sem esse case, o 0 cairia no default e mostraria "Opção inválida". |
$ g++ -std=c++23 -Wall -Wextra agenda.cpp -o agenda $ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 0. Sair Opção: 2 --- Contatos (2) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com 1. Adicionar 2. Listar 0. Sair Opção: 1 Nome: Carla Dias Telefone: (31) 90000-0003 E-mail: carla@exemplo.com Contato adicionado: Carla Dias 1. Adicionar 2. Listar 0. Sair Opção: 2 --- Contatos (3) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com 3. Carla Dias | (31) 90000-0003 | carla@exemplo.com 1. Adicionar 2. Listar 0. Sair Opção: 7 Opção inválida. 1. Adicionar 2. Listar 0. Sair Opção: 0 Até logo!
Por que o std::ws: o getline que "pula" a pergunta
Na primeira versão, a Ana escreveu só std::getline(std::cin, novo.nome);. Veja o que aconteceu:
$ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 0. Sair Opção: 1 Nome: Telefone: Carla Dias « o "Nome:" não esperou! E-mail: (31) 90000-0003 Contato adicionado: 1. Adicionar 2. Listar 0. Sair Opção: 2 --- Contatos (3) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com 3. | Carla Dias | (31) 90000-0003 « nome vazio, e tudo deslocado uma casa
Quando a Ana digitou 1 e apertou Enter, a entrada recebeu dois caracteres: o 1 e uma quebra de linha (\n). O std::cin >> opcao leu o 1 e deixou o \n lá. Aí o getline do nome, que lê "até o fim da linha", encontrou o \n imediatamente e leu uma linha vazia, sem esperar. O nome digitado foi parar no telefone, o telefone no e-mail.
O std::ws (de whitespace, "espaço em branco") resolve: std::cin >> std::ws descarta espaços e quebras de linha que estejam esperando, e só então o getline lê. Esse problema de misturar >> e getline é tão comum que tem uma seção só para ele na aula getline.
Missão (etapa 2): este código tem o problema do getline que "pula" a pergunta. Rode e veja o contato sair torto na listagem. Depois conserte as três leituras do adicionar com std::cin >> std::ws. A entrada adiciona a Carla Dias e lista.
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 0: break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 0: break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
Etapa 3 · Buscar sem diferenciar maiúsculas
Com muitos contatos, a Ana quer digitar um pedaço do nome e ver só quem combina. A primeira ideia: percorrer a lista e perguntar se o nome contém o texto buscado. O C++23 tem um método para isso, contains (veja Funções de String; em versões antigas, usa-se nome.find(busca) != std::string::npos):
if (agenda[i].nome.contains(busca)) {
$ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 3 Buscar por: ana Nenhum contato encontrado com "ana". 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 3 Buscar por: Ana 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 0 Até logo!
Funciona, mas só com a letra maiúscula certa: para o computador, a e A são caracteres diferentes. A solução é comparar as duas coisas em minúsculas: o nome e o texto buscado. Para isso, uma função que troca cada letra pela minúscula:
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
- std::string minusculas(std::string texto)
- Aqui o parâmetro é por valor, de propósito: a função recebe uma cópia, muda a cópia e a devolve. O nome original do contato fica intacto.
- for (char& letra : texto)
- Percorre cada caractere por referência (
&), para poder trocá-lo dentro do texto. - std::tolower(…)
- De to lower, "para minúscula": devolve a minúscula de uma letra (
'A'→'a') e devolve qualquer outro caractere sem mudar. Vem do<cctype>. - static_cast<unsigned char>(letra)
- Um detalhe chato, mas importante: o
tolowersó aceita valores de 0 a 255, e umcharcom acento pode ser negativo. Converter paraunsigned charantes evita comportamento indefinido (veja Conversão de Tipos). Ostatic_cast<char>de fora converte o resultado de volta parachar. - const std::string procurado = minusculas(busca);
- Converte o texto buscado uma vez só, antes do laço.
- minusculas(agenda[i].nome).contains(procurado)
- "O nome, em minúsculas, contém o texto procurado, em minúsculas?"
- int encontrados
- Conta quantos combinaram, para avisar quando não houver nenhum.
$ g++ -std=c++23 -Wall -Wextra agenda.cpp -o agenda $ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 3 Buscar por: ana 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 3 Buscar por: LI 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 3 Buscar por: zé Nenhum contato encontrado com "zé". 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 1 Nome: Érica Melo Telefone: (41) 90000-0004 E-mail: erica@exemplo.com Contato adicionado: Érica Melo 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 3 Buscar por: érica Nenhum contato encontrado com "érica". « o acento atrapalhou 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 3 Buscar por: rica 3. Érica Melo | (41) 90000-0004 | erica@exemplo.com 1. Adicionar 2. Listar 3. Buscar 0. Sair Opção: 0 Até logo!
A busca encontrou "Ana" com ana e "Lima" com LI, mas não encontrou "Érica" com érica. O motivo: no UTF-8, que é como o Linux guarda o texto, uma letra acentuada como É ocupa dois char, e o tolower olha um char de cada vez. Ele só sabe converter as 26 letras sem acento (a tabela ASCII). Resolver isso direito exige uma biblioteca especializada; a aula Acentos e UTF-8 explica o porquê. Para a agenda da Ana, buscar pela parte sem acento (rica) é suficiente.
Missão (etapa 3): a função minusculas já existe, mas a busca ainda compara o texto exato. Mude a condição do if no buscar para comparar minusculas(agenda[i].nome) com procurado. A entrada busca ana, em minúsculas.
#include <cctype>
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (agenda[i].nome.contains(busca)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 0: break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
#include <cctype>
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 0: break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
Etapa 4 · Remover
Para remover, a agenda mostra a lista numerada, pergunta o número e apaga aquele contato. O cuidado principal é com o número: ele precisa existir na lista.
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
E no switch do main, uma linha nova: case 4: remover(agenda); break;.
- if (!(std::cin >> numero) || numero < 1 || numero > agenda.size())
- Três motivos para recusar: a leitura falhou (texto), o número é menor que 1, ou é maior que a quantidade de contatos. O
||para no primeiro que for verdadeiro. - agenda[numero - 1].nome
- O contato número 1 está na posição 0. Pegamos o nome antes de apagar, para mostrar a mensagem.
- agenda.erase(agenda.begin() + (numero - 1));
erase("apagar") remove um elemento dovector, e os seguintes andam uma posição para trás. Ele não recebe uma posição, e sim um iterador:agenda.begin()aponta para o primeiro elemento, e+ (numero - 1)anda até o escolhido.
$ g++ -std=c++23 -Wall -Wextra agenda.cpp -o agenda $ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 4 --- Contatos (2) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com Número do contato a remover: 2 Removido: Bruno Lima 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 2 --- Contatos (1) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 4 --- Contatos (1) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com Número do contato a remover: 9 Número inválido. 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 4 --- Contatos (1) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com Número do contato a remover: abc Número inválido. 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 0 Até logo!
Numa versão sem o if de validação (só std::cin >> numero;), a Ana digitou 9 numa agenda com 2 contatos:
$ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 4 --- Contatos (2) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com Número do contato a remover: 9 /usr/include/c++/15/bits/stl_vector.h:1263: constexpr std::vector< <template-parameter-1-1>, <template-parameter-1-2> >::reference std::vector< <template-parameter-1-1>, <template-parameter-1-2> >::operator[](size_type) [with _Tp = Contato; _Alloc = std::allocator<Contato>; reference = Contato&; size_type = long unsigned int]: Assertion '__n < this->size()' failed. Abortado (imagem do núcleo gravada) ./agenda $ echo $? 134
O que significa: o agenda[numero - 1] tentou ler a posição 8 de uma lista com 2 elementos. A mensagem enorme vem de dentro do vector (stl_vector.h), e o que importa está no fim: Assertion '__n < this->size()' failed, "a verificação 'posição menor que o tamanho' falhou". O g++ do Ubuntu liga essa verificação por padrão, e o programa é abortado na hora (código de saída 134). Em outros compiladores ou configurações, a verificação pode não existir: aí é comportamento indefinido, e o programa pode mostrar lixo ou apagar o contato errado.
Como consertar: confira o número antes de usá-lo, como no código da etapa. Os contatos que a Ana tinha digitado nessa sessão foram perdidos: mais um motivo para a etapa 5.
Missão (etapa 4): a função remover já mostra a lista, lê e valida o número. Complete o final: mostre Removido: com o nome do contato e apague-o com agenda.erase(agenda.begin() + (numero - 1));. A entrada remove o contato 2 e lista.
#include <cctype>
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
// mostre "Removido: " e o nome, e apague o contato da agenda
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
#include <cctype>
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
Etapa 5 · Salvar no arquivo
Até agora, tudo o que a Ana digita some quando o programa fecha: as variáveis vivem na memória, e a memória do programa é devolvida ao sistema no fim. Para guardar de verdade, os contatos precisam ir para um arquivo no disco.
Primeiro, decidimos o formato do arquivo. O mais simples: um contato por linha, com os campos separados por ponto e vírgula. É parecido com um arquivo CSV (o formato das planilhas), e dá para abrir e ler num editor de texto:
Ana Souza;(11) 90000-0001;ana@exemplo.com Bruno Lima;(21) 90000-0002;bruno@exemplo.com
Por que ponto e vírgula e não vírgula? Porque vírgula aparece em nomes e endereços com mais frequência. Para gravar, usamos um std::ofstream (de output file stream, "fluxo de saída para arquivo"), que funciona como o cout, mas escreve num arquivo (veja Ler e Escrever Arquivos):
#include <fstream> // novo: ofstream e ifstream
// ...
const std::string arquivo_agenda = "agenda.txt";
void salvar(const std::vector<Contato>& agenda) {
std::ofstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Não consegui abrir " << arquivo_agenda << " para gravar.\n";
return;
}
for (const Contato& c : agenda) {
arquivo << c.nome << ';' << c.telefone << ';' << c.email << '\n';
}
std::cout << "Agenda salva em " << arquivo_agenda << " (" << agenda.size() << " contatos).\n";
}
E no main, a opção 0 passa a salvar antes de sair: case 0: salvar(agenda); break;.
- #include <fstream>
- O cabeçalho dos arquivos:
std::ofstream(escrever) estd::ifstream(ler). - const std::string arquivo_agenda = "agenda.txt";
- O nome do arquivo numa constante, fora das funções:
salvare (na próxima etapa)carregarusam o mesmo nome, escrito num lugar só. O arquivo fica na pasta onde o programa roda. - std::ofstream arquivo(arquivo_agenda);
- Abre o arquivo para escrita. Se ele não existe, é criado; se existe, é apagado e reescrito do zero. Como sempre gravamos a agenda inteira, é exatamente o que queremos.
- if (!arquivo)
- Confere se abriu. Pode falhar se a pasta não deixar gravar, por exemplo.
- arquivo << c.nome << ';' << …
- Escreve como no
cout: nome,;, telefone,;, e-mail e a quebra de linha. - (fim da função)
- Não há
close(): quando a variávelarquivosai de escopo, no fim da função, oofstreamfecha o arquivo sozinho. É o RAII (veja Destrutores e RAII).
$ g++ -std=c++23 -Wall -Wextra agenda.cpp -o agenda $ ./agenda === Agenda da Ana === 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 1 Nome: Carla Dias Telefone: (31) 90000-0003 E-mail: carla@exemplo.com Contato adicionado: Carla Dias 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 0 Agenda salva em agenda.txt (3 contatos). Até logo! $ cat agenda.txt « o cat mostra o conteúdo do arquivo Ana Souza;(11) 90000-0001;ana@exemplo.com Bruno Lima;(21) 90000-0002;bruno@exemplo.com Carla Dias;(31) 90000-0003;carla@exemplo.com
#include <fstream>
$ g++ -std=c++23 -Wall -Wextra agenda.cpp -o agenda
agenda.cpp: In function ‘void salvar(const std::vector<Contato>&)’:
agenda.cpp:101:41: error: variable ‘std::ofstream arquivo’ has initializer but incomplete type
101 | std::ofstream arquivo(arquivo_agenda);
| ^
agenda.cpp:5:1: note: ‘std::ofstream’ is defined in header ‘<fstream>’; this is probably fixable by adding ‘#include <fstream>’
4 | #include <vector>
+++ |+#include <fstream>
5 |
O que significa: "a variável arquivo tem valor inicial, mas o tipo está incompleto": o compilador sabe que std::ofstream existe (o <iostream> o anuncia), mas não sabe como ele é por dentro. A nota é ótima: diz que std::ofstream é definido em <fstream> e até mostra, com +++ |+, onde colocar a linha.
Como consertar: #include <fstream>.
Missão (etapa 5): a função salvar está vazia. Abra o arquivo com std::ofstream, grave cada contato numa linha no formato nome;telefone;email e mostre Agenda salva em agenda.txt (3 contatos). (o 3 vem de agenda.size()). A entrada adiciona a Carla e escolhe 0.
#include <cctype>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
const std::string arquivo_agenda = "agenda.txt";
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
void salvar(const std::vector<Contato>& agenda) {
// grave cada contato numa linha do arquivo, no formato nome;telefone;email
// e mostre: Agenda salva em agenda.txt (N contatos).
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: salvar(agenda); break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
#include <cctype>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
const std::string arquivo_agenda = "agenda.txt";
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
void salvar(const std::vector<Contato>& agenda) {
std::ofstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Não consegui abrir " << arquivo_agenda << " para gravar.\n";
return;
}
for (const Contato& c : agenda) {
arquivo << c.nome << ';' << c.telefone << ';' << c.email << '\n';
}
std::cout << "Agenda salva em " << arquivo_agenda << " (" << agenda.size() << " contatos).\n";
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda{
{"Ana Souza", "(11) 90000-0001", "ana@exemplo.com"},
{"Bruno Lima", "(21) 90000-0002", "bruno@exemplo.com"},
};
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: salvar(agenda); break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
Etapa 6 · Carregar do arquivo
O arquivo já é gravado; falta lê-lo quando o programa abre. A lista inicial com a Ana e o Bruno escrita no código sai de cena: a agenda começa com o que estiver no arquivo. Para ler, um std::ifstream (input file stream, "fluxo de entrada de arquivo"), que funciona como o cin. E para separar os campos de cada linha, um truque: transformar a linha num "mini cin" com std::istringstream e usar o getline com o ; como separador.
#include <sstream> // novo: istringstream
// ...
std::vector<Contato> carregar() {
std::vector<Contato> agenda;
std::ifstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Nenhuma agenda salva ainda (" << arquivo_agenda << " não existe).\n";
return agenda;
}
std::string linha;
while (std::getline(arquivo, linha)) {
std::istringstream campos(linha);
Contato c;
std::getline(campos, c.nome, ';');
std::getline(campos, c.telefone, ';');
std::getline(campos, c.email);
if (!c.nome.empty()) {
agenda.push_back(c);
}
}
std::cout << "Carregados " << agenda.size() << " contatos de " << arquivo_agenda << ".\n";
return agenda;
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda = carregar();
// ... (o resto do main não muda)
- std::ifstream arquivo(arquivo_agenda); if (!arquivo)
- Abre para leitura. Na primeira vez que a agenda roda, o arquivo ainda não existe e a abertura falha. Isso não é um erro: só avisamos e devolvemos a agenda vazia.
- while (std::getline(arquivo, linha))
- Lê o arquivo linha por linha. O
getlinedevolve "falso" quando o arquivo acaba, e o laço termina. - std::istringstream campos(linha);
- Um fluxo de entrada que lê de uma
std::stringem vez do teclado (vem do<sstream>; veja Texto ↔ Número). Assim podemos usargetlinedentro da linha. - std::getline(campos, c.nome, ';');
- O terceiro argumento muda o separador: em vez de ler até o fim da linha, lê até o
;. Primeiro o nome, depois o telefone… - std::getline(campos, c.email);
- …e o e-mail, que é o resto da linha.
- if (!c.nome.empty())
- Pula linhas vazias (por exemplo, uma linha em branco no fim do arquivo, se alguém o editar à mão).
- std::vector<Contato> agenda = carregar();
- No
main, a agenda nasce com o que a função devolveu.
A primeira vez, sem arquivo, e a segunda vez, com o arquivo gravado pela primeira:
$ g++ -std=c++23 -Wall -Wextra agenda.cpp -o agenda $ rm agenda.txt « apaga o arquivo da etapa 5, para começar do zero $ ./agenda === Agenda da Ana === Nenhuma agenda salva ainda (agenda.txt não existe). 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 1 Nome: Ana Souza Telefone: (11) 90000-0001 E-mail: ana@exemplo.com Contato adicionado: Ana Souza 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 1 Nome: Bruno Lima Telefone: (21) 90000-0002 E-mail: bruno@exemplo.com Contato adicionado: Bruno Lima 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 0 Agenda salva em agenda.txt (2 contatos). Até logo! $ ./agenda === Agenda da Ana === Carregados 2 contatos de agenda.txt. « os contatos sobreviveram ao fim do programa 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 2 --- Contatos (2) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 0 Agenda salva em agenda.txt (2 contatos). Até logo!
; dentro do nome bagunça o arquivo
A Ana cadastrou um cliente como Dias; Carla (sobrenome primeiro). A agenda salvou sem reclamar, mas na próxima abertura:
$ cat agenda.txt Ana Souza;(11) 90000-0001;ana@exemplo.com Bruno Lima;(21) 90000-0002;bruno@exemplo.com Dias; Carla;(31) 90000-0003;carla@exemplo.com $ ./agenda | head -9 « (a Ana escolheu 2 e depois 0) === Agenda da Ana === Carregados 3 contatos de agenda.txt. 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 2 --- Contatos (3) --- 1. Ana Souza | (11) 90000-0001 | ana@exemplo.com 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com 3. Dias | Carla | (31) 90000-0003;carla@exemplo.com
O que significa: o ; do nome foi confundido com o separador. O nome virou Dias, o telefone virou Carla, e o resto da linha caiu no e-mail. Todo formato com separador tem esse problema: o separador não pode aparecer dentro dos dados.
Como consertar: no adicionar, recuse (ou troque) o ; nos campos. É o desafio 2 abaixo. Formatos profissionais, como o CSV de verdade e o JSON, resolvem isso com aspas e "escapes" (veja Caracteres Especiais).
Missão (etapa 6): o arquivo agenda.txt (na segunda aba) já tem três contatos, mas a função carregar só devolve uma agenda vazia. Escreva a leitura: abra com std::ifstream, leia cada linha com getline, separe os campos com std::istringstream e getline(campos, …, ';'), e mostre Carregados 3 contatos de agenda.txt.. A entrada lista e sai.
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
const std::string arquivo_agenda = "agenda.txt";
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
void salvar(const std::vector<Contato>& agenda) {
std::ofstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Não consegui abrir " << arquivo_agenda << " para gravar.\n";
return;
}
for (const Contato& c : agenda) {
arquivo << c.nome << ';' << c.telefone << ';' << c.email << '\n';
}
std::cout << "Agenda salva em " << arquivo_agenda << " (" << agenda.size() << " contatos).\n";
}
std::vector<Contato> carregar() {
std::vector<Contato> agenda;
// abra o arquivo, leia linha por linha, separe os campos pelo ';'
// e mostre: Carregados N contatos de agenda.txt.
return agenda;
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda = carregar();
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: salvar(agenda); break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
Ana Souza;(11) 90000-0001;ana@exemplo.com Bruno Lima;(21) 90000-0002;bruno@exemplo.com Carla Dias;(31) 90000-0003;carla@exemplo.com
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
const std::string arquivo_agenda = "agenda.txt";
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
void salvar(const std::vector<Contato>& agenda) {
std::ofstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Não consegui abrir " << arquivo_agenda << " para gravar.\n";
return;
}
for (const Contato& c : agenda) {
arquivo << c.nome << ';' << c.telefone << ';' << c.email << '\n';
}
std::cout << "Agenda salva em " << arquivo_agenda << " (" << agenda.size() << " contatos).\n";
}
std::vector<Contato> carregar() {
std::vector<Contato> agenda;
std::ifstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Nenhuma agenda salva ainda (" << arquivo_agenda << " não existe).\n";
return agenda;
}
std::string linha;
while (std::getline(arquivo, linha)) {
std::istringstream campos(linha);
Contato c;
std::getline(campos, c.nome, ';');
std::getline(campos, c.telefone, ';');
std::getline(campos, c.email);
if (!c.nome.empty()) {
agenda.push_back(c);
}
}
std::cout << "Carregados " << agenda.size() << " contatos de " << arquivo_agenda << ".\n";
return agenda;
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda = carregar();
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: salvar(agenda); break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
O código completo
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
const std::string arquivo_agenda = "agenda.txt";
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
void salvar(const std::vector<Contato>& agenda) {
std::ofstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Não consegui abrir " << arquivo_agenda << " para gravar.\n";
return;
}
for (const Contato& c : agenda) {
arquivo << c.nome << ';' << c.telefone << ';' << c.email << '\n';
}
std::cout << "Agenda salva em " << arquivo_agenda << " (" << agenda.size() << " contatos).\n";
}
std::vector<Contato> carregar() {
std::vector<Contato> agenda;
std::ifstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Nenhuma agenda salva ainda (" << arquivo_agenda << " não existe).\n";
return agenda;
}
std::string linha;
while (std::getline(arquivo, linha)) {
std::istringstream campos(linha);
Contato c;
std::getline(campos, c.nome, ';');
std::getline(campos, c.telefone, ';');
std::getline(campos, c.email);
if (!c.nome.empty()) {
agenda.push_back(c);
}
}
std::cout << "Carregados " << agenda.size() << " contatos de " << arquivo_agenda << ".\n";
return agenda;
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda = carregar();
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: salvar(agenda); break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
O projeto juntou struct, vector (push_back, erase, size), switch num while, getline com std::ws, funções de string, referências (const& para ler, & para mudar) e arquivos. O padrão "carregar no começo, salvar no fim" é o de muitos programas de verdade, de editores de texto a jogos.
Desafios extras
- Buscar também pelo telefone. Faça a busca encontrar o contato quando o texto aparecer no nome ou no telefone. (Faça no editor, logo abaixo.)
- Nada de
;nos campos. Noadicionar, se algum campo tiver;, mostre um aviso e peça de novo (dica:campo.contains(';')). - Lista em ordem alfabética. Depois de adicionar, ordene a agenda pelo nome com
std::ranges::sorte uma lambda (veja Algoritmos). - Editar. Uma opção 5 que pergunta o número do contato e deixa trocar o telefone e o e-mail.
- Confirmar antes de remover. "Remover Bruno Lima? (s/n)".
- Salvar sempre. Hoje, se o programa for fechado com Ctrl+C, as mudanças da sessão se perdem. Chame
salvarlogo depois de cada adição e remoção.
Desafio 1 no editor: mude a condição da busca para também aceitar quando agenda[i].telefone contiver o texto procurado (use ||, o "ou"). A entrada busca 90000-0002, o telefone do Bruno.
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
const std::string arquivo_agenda = "agenda.txt";
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
void salvar(const std::vector<Contato>& agenda) {
std::ofstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Não consegui abrir " << arquivo_agenda << " para gravar.\n";
return;
}
for (const Contato& c : agenda) {
arquivo << c.nome << ';' << c.telefone << ';' << c.email << '\n';
}
std::cout << "Agenda salva em " << arquivo_agenda << " (" << agenda.size() << " contatos).\n";
}
std::vector<Contato> carregar() {
std::vector<Contato> agenda;
std::ifstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Nenhuma agenda salva ainda (" << arquivo_agenda << " não existe).\n";
return agenda;
}
std::string linha;
while (std::getline(arquivo, linha)) {
std::istringstream campos(linha);
Contato c;
std::getline(campos, c.nome, ';');
std::getline(campos, c.telefone, ';');
std::getline(campos, c.email);
if (!c.nome.empty()) {
agenda.push_back(c);
}
}
std::cout << "Carregados " << agenda.size() << " contatos de " << arquivo_agenda << ".\n";
return agenda;
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda = carregar();
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: salvar(agenda); break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
Ana Souza;(11) 90000-0001;ana@exemplo.com Bruno Lima;(21) 90000-0002;bruno@exemplo.com Carla Dias;(31) 90000-0003;carla@exemplo.com
#include <cctype>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
struct Contato {
std::string nome;
std::string telefone;
std::string email;
};
const std::string arquivo_agenda = "agenda.txt";
void mostrar(std::size_t numero, const Contato& c) {
std::cout << numero << ". " << c.nome << " | " << c.telefone << " | " << c.email << '\n';
}
void listar(const std::vector<Contato>& agenda) {
if (agenda.empty()) {
std::cout << "A agenda está vazia.\n";
return;
}
std::cout << "--- Contatos (" << agenda.size() << ") ---\n";
for (std::size_t i = 0; i < agenda.size(); ++i) {
mostrar(i + 1, agenda[i]);
}
}
int ler_opcao() {
int opcao = -1;
std::cout << "Opção: ";
if (!(std::cin >> opcao)) {
if (std::cin.eof()) {
return 0; // a entrada acabou: sai (e salva)
}
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
return -1; // não era número: opção inválida
}
return opcao;
}
void adicionar(std::vector<Contato>& agenda) {
Contato novo;
std::cout << "Nome: ";
std::getline(std::cin >> std::ws, novo.nome);
std::cout << "Telefone: ";
std::getline(std::cin >> std::ws, novo.telefone);
std::cout << "E-mail: ";
std::getline(std::cin >> std::ws, novo.email);
agenda.push_back(novo);
std::cout << "Contato adicionado: " << novo.nome << '\n';
}
// Devolve uma cópia do texto com as letras A-Z trocadas por a-z.
std::string minusculas(std::string texto) {
for (char& letra : texto) {
letra = static_cast<char>(std::tolower(static_cast<unsigned char>(letra)));
}
return texto;
}
void buscar(const std::vector<Contato>& agenda) {
std::string busca;
std::cout << "Buscar por: ";
std::getline(std::cin >> std::ws, busca);
const std::string procurado = minusculas(busca);
int encontrados = 0;
for (std::size_t i = 0; i < agenda.size(); ++i) {
if (minusculas(agenda[i].nome).contains(procurado) || agenda[i].telefone.contains(procurado)) {
mostrar(i + 1, agenda[i]);
++encontrados;
}
}
if (encontrados == 0) {
std::cout << "Nenhum contato encontrado com \"" << busca << "\".\n";
}
}
void remover(std::vector<Contato>& agenda) {
listar(agenda);
if (agenda.empty()) {
return;
}
std::cout << "Número do contato a remover: ";
std::size_t numero = 0;
if (!(std::cin >> numero) || numero < 1 || numero > agenda.size()) {
std::cin.clear();
std::string lixo;
std::getline(std::cin, lixo);
std::cout << "Número inválido.\n";
return;
}
std::cout << "Removido: " << agenda[numero - 1].nome << '\n';
agenda.erase(agenda.begin() + (numero - 1));
}
void salvar(const std::vector<Contato>& agenda) {
std::ofstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Não consegui abrir " << arquivo_agenda << " para gravar.\n";
return;
}
for (const Contato& c : agenda) {
arquivo << c.nome << ';' << c.telefone << ';' << c.email << '\n';
}
std::cout << "Agenda salva em " << arquivo_agenda << " (" << agenda.size() << " contatos).\n";
}
std::vector<Contato> carregar() {
std::vector<Contato> agenda;
std::ifstream arquivo(arquivo_agenda);
if (!arquivo) {
std::cout << "Nenhuma agenda salva ainda (" << arquivo_agenda << " não existe).\n";
return agenda;
}
std::string linha;
while (std::getline(arquivo, linha)) {
std::istringstream campos(linha);
Contato c;
std::getline(campos, c.nome, ';');
std::getline(campos, c.telefone, ';');
std::getline(campos, c.email);
if (!c.nome.empty()) {
agenda.push_back(c);
}
}
std::cout << "Carregados " << agenda.size() << " contatos de " << arquivo_agenda << ".\n";
return agenda;
}
int main() {
std::cout << "=== Agenda da Ana ===\n";
std::vector<Contato> agenda = carregar();
int opcao = -1;
while (opcao != 0) {
std::cout << "\n1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair\n";
opcao = ler_opcao();
switch (opcao) {
case 1: adicionar(agenda); break;
case 2: listar(agenda); break;
case 3: buscar(agenda); break;
case 4: remover(agenda); break;
case 0: salvar(agenda); break;
default: std::cout << "Opção inválida.\n";
}
}
std::cout << "Até logo!\n";
}
Na máquina da Ana, com o arquivo de três contatos:
$ ./agenda === Agenda da Ana === Carregados 3 contatos de agenda.txt. 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 3 Buscar por: 90000-0002 2. Bruno Lima | (21) 90000-0002 | bruno@exemplo.com 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 3 Buscar por: carla 3. Carla Dias | (31) 90000-0003 | carla@exemplo.com 1. Adicionar 2. Listar 3. Buscar 4. Remover 0. Sair Opção: 0 Agenda salva em agenda.txt (3 contatos). Até logo!
Exercícios
1. Depois de std::cin >> opcao;, um std::getline(std::cin, nome); leu um nome vazio sem esperar. Por quê?
2. Por que adicionar recebe std::vector<Contato>& agenda (com & e sem const)?
3. O que acontece com o conteúdo antigo de agenda.txt quando std::ofstream arquivo("agenda.txt"); abre o arquivo?
4. Por que a busca não acha "Érica" quando a Ana digita "érica"?
5. Complete a leitura do telefone, que vai até o próximo ;:
6. Complete para ler uma linha inteira depois de um cin >>, descartando a quebra de linha que sobrou:
Resumo
- Uma
structjunta as informações de um contato; umstd::vectorguarda quantos forem precisos. - Menu =
while (opcao != 0)+switch+ uma função por opção. - Para ler uma linha com espaços depois de um
>>:std::getline(std::cin >> std::ws, texto). - Busca sem diferenciar maiúsculas: compare tudo em minúsculas (
std::tolowercomunsigned char). Só funciona para letras sem acento. - Antes de usar um número digitado como posição, confira se ele existe na lista.
erase(begin() + posição)remove. std::ofstreamgrava (e apaga o conteúdo antigo);std::ifstreamlê;std::istringstream+getline(…, ';')separa os campos. Os arquivos fecham sozinhos.- O separador (
;) não pode aparecer dentro dos dados.
Próximo projeto: Contas Bancárias (POO), em que os dados ganham regras próprias dentro de classes.