Lista 03 · Structs e enum class¶
Exercícios da Semana 3 — Structs e enum class. Aqui você cria seus próprios tipos com struct e começa a escrever métodos dentro deles — é o primeiro passo em direção às classes da Unidade 5.
Como resolver
Copie o bloco de código de cada exercício, cole no seu compilador online, preencha a parte marcada como ESCREVA SUA SOLUCAO AQUI e rode. A saída mostra quais testes passaram.
ex01¶
Complete a struct Intervalo (campos inicio e fim, ambos double, já declarados) implementando os métodos duracao() e contem(double valor), ambos const.
duracao()devolvefim - inicio.contem(valor)devolvetruese o valor estiver dentro do intervalo, contando as duas pontas:inicio <= valor && valor <= fim.
Repare que os dois métodos são const: eles respondem perguntas sobre o intervalo sem alterá-lo. Marcar isso não é firula — é o que permite chamá-los sobre um const Intervalo&, e é o que avisa a quem lê que a struct sai da chamada exatamente como entrou.
contem precisa de duas comparações ligadas por &&. Escrever inicio <= valor <= fim compila em C++ e dá a resposta errada: o compilador lê isso como (inicio <= valor) <= fim, ou seja, compara um true/false com um double.
Intervalo aula{8.0, 10.0};
aula.duracao(); // -> 2.0
aula.contem(9.0); // -> true
aula.contem(8.0); // -> true (a ponta conta)
aula.contem(11.0); // -> false
// ex01 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <cmath>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX01_H
#define EX01_H
struct Intervalo {
double inicio;
double fim;
double duracao() const;
bool contem(double valor) const;
};
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
double Intervalo::duracao() const {
// TODO: retorne fim - inicio.
return 0.0;
}
bool Intervalo::contem(double valor) const {
// TODO: retorne true se valor estiver entre inicio e fim,
// incluindo as duas pontas. Sao DUAS comparacoes, ligadas por &&.
return false;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
Intervalo aula{8.0, 10.0};
assert(std::abs(aula.duracao() - 2.0) <= 0.0001);
assert(aula.contem(9.0));
assert(aula.contem(8.0)); // a ponta de baixo conta
assert(aula.contem(10.0)); // a ponta de cima tambem
assert(!aula.contem(7.9));
assert(!aula.contem(11.0));
// intervalo com inicio negativo
Intervalo temperatura{-5.0, 5.0};
assert(std::abs(temperatura.duracao() - 10.0) <= 0.0001);
assert(temperatura.contem(0.0));
assert(temperatura.contem(-5.0));
assert(!temperatura.contem(-6.0));
// intervalo de duracao zero: contem apenas o proprio ponto
Intervalo instante{3.0, 3.0};
assert(std::abs(instante.duracao() - 0.0) <= 0.0001);
assert(instante.contem(3.0));
assert(!instante.contem(3.1));
// os metodos sao const: precisam funcionar sobre uma referencia const
const Intervalo& constante = aula;
assert(constante.contem(9.0));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex02¶
Dado o enum class Turno { Manha, Tarde, Noite } (já declarado), escreva nome_turno, que devolve o nome por extenso de cada valor.
nome_turno(Turno::Manha) // -> "Manha"
nome_turno(Turno::Tarde) // -> "Tarde"
nome_turno(Turno::Noite) // -> "Noite"
// ex02 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX02_H
#define EX02_H
enum class Turno { Manha, Tarde, Noite };
// Retorna o nome por extenso do turno.
std::string nome_turno(Turno t);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::string nome_turno(Turno t) {
// TODO: use um if/else (ou switch) comparando t com Turno::Manha, Turno::Tarde, Turno::Noite.
return "";
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(nome_turno(Turno::Manha) == std::string("Manha"));
assert(nome_turno(Turno::Tarde) == std::string("Tarde"));
assert(nome_turno(Turno::Noite) == std::string("Noite"));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex03¶
Escreva min_max, que recebe três inteiros e devolve um std::pair<int, int> com o menor valor em .first e o maior em .second.
// ex03 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <utility>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX03_H
#define EX03_H
// Retorna {menor, maior} entre os tres valores.
std::pair<int, int> min_max(int a, int b, int c);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::pair<int, int> min_max(int a, int b, int c) {
// TODO: monte um pair {menor, maior} entre a, b e c.
return {0, 0};
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
auto r1 = min_max(3, 9, 5);
assert(r1.first == 3);
assert(r1.second == 9);
auto r2 = min_max(-1, -5, 0);
assert(r2.first == -5);
assert(r2.second == 0);
auto r3 = min_max(4, 4, 4);
assert(r3.first == 4);
assert(r3.second == 4);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex04¶
Escreva converte_para_int, que recebe um texto e o converte para inteiro. Como a conversão pode simplesmente não ter resposta (o texto pode não ser um número), a função devolve bool dizendo se deu certo, e escreve o número num parâmetro por referência — o padrão da Aula 02.
As regras do que é válido:
- pode começar com um
-, indicando número negativo (mas um-sozinho não é número); - o resto tem que ser só dígitos, pelo menos um;
- texto vazio, com espaços, com letras ou com ponto decimal é inválido.
Quando o texto for inválido, devolva false e não mexa no parâmetro de saída.
Para converter, percorra os dígitos da esquerda para a direita acumulando resultado = resultado * 10 + digito. Um char de dígito vira o número que ele representa com c - '0': '7' - '0' dá 7, porque os dígitos são consecutivos na tabela de caracteres. Para testar se um char é dígito, c >= '0' && c <= '9'.
Não use std::stoi: ela aborta o programa em vez de avisar, e aceita coisas como "12abc" (converte os 12 e ignora o resto) — exatamente o que este exercício quer rejeitar.
int valor;
converte_para_int("42", valor) // -> true, e valor vale 42
converte_para_int("-7", valor) // -> true, e valor vale -7
converte_para_int("007", valor) // -> true, e valor vale 7
converte_para_int("12a", valor) // -> false
converte_para_int("", valor) // -> false
converte_para_int("-", valor) // -> false
// ex04 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX04_H
#define EX04_H
// Converte texto para int. Aceita um '-' inicial seguido de pelo menos um
// digito, e nada alem de digitos depois disso.
// Devolve true e escreve em "valor" se o texto for um inteiro valido;
// devolve false e nao mexe em "valor" caso contrario.
bool converte_para_int(const std::string& texto, int& valor);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
bool converte_para_int(const std::string& texto, int& valor) {
// TODO:
// 1. texto vazio -> devolva false.
// 2. se comecar com '-', guarde que e negativo e comece a ler do indice 1;
// senao comece do indice 0. Se nao sobrar nenhum caractere, false.
// 3. percorra os caracteres restantes: se algum nao for digito
// (c >= '0' && c <= '9'), devolva false;
// senao faca resultado = resultado * 10 + (c - '0').
// 4. escreva o resultado com o sinal em "valor" e devolva true.
return false;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
int v = 0;
assert(converte_para_int("42", v));
assert(v == 42);
assert(converte_para_int("0", v));
assert(v == 0);
assert(converte_para_int("7", v));
assert(v == 7);
// zeros a esquerda sao aceitos
assert(converte_para_int("007", v));
assert(v == 7);
// negativos
assert(converte_para_int("-7", v));
assert(v == -7);
assert(converte_para_int("-1234", v));
assert(v == -1234);
// invalidos: devolvem false e nao mexem no parametro de saida
v = 99;
assert(!converte_para_int("", v));
assert(v == 99);
assert(!converte_para_int("-", v));
assert(!converte_para_int("12a", v));
assert(!converte_para_int("a12", v));
assert(!converte_para_int("1 2", v));
assert(!converte_para_int(" 12", v));
assert(!converte_para_int("3.14", v));
assert(!converte_para_int("--5", v));
assert(!converte_para_int("5-", v));
assert(v == 99);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex05¶
Complete a struct Aluno (campos nome e nota, já declarados) implementando o método aprovado() const, que devolve true se nota >= 6.0.
// ex05 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX05_H
#define EX05_H
struct Aluno {
std::string nome;
double nota;
bool aprovado() const;
};
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
bool Aluno::aprovado() const {
// TODO: retorne true se nota >= 6.0.
return false;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
Aluno a{"Carlos", 7.5};
assert(a.aprovado());
Aluno b{"Marcia", 5.0};
assert(!(b.aprovado()));
Aluno c{"Julia", 6.0};
assert(c.aprovado());
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex06¶
Escreva busca_posicao, que recebe um texto e um caractere alvo, e devolve a posição (índice) da primeira ocorrência do caractere — ou -1 se o caractere não aparecer.
O -1 funciona bem aqui por um motivo específico: nenhuma posição válida é negativa, então -1 nunca se confunde com uma resposta de verdade. Guarde essa observação; ela não vale para toda função.
// ex06 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX06_H
#define EX06_H
// Retorna a posicao da primeira ocorrencia de "alvo" em "texto",
// ou -1 se o caractere nao aparecer.
int busca_posicao(const std::string& texto, char alvo);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
int busca_posicao(const std::string& texto, char alvo) {
// TODO: percorra "texto"; se achar "alvo", retorne o indice.
// Se terminar o laco sem achar, retorne -1.
return -1;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(busca_posicao("programacao", 'g') == 3);
assert(busca_posicao("programacao", 'z') == -1);
assert(busca_posicao("abc", 'a') == 0);
assert(busca_posicao("", 'a') == -1);
// devolve a PRIMEIRA ocorrencia
assert(busca_posicao("banana", 'a') == 1);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex07¶
Dada a struct Intervalo (campos inicio e fim, ambos double, já declarada — a mesma do ex01), escreva intersecao, que recebe dois intervalos e escreve num terceiro parâmetro a parte em que os dois se sobrepõem. A função devolve bool: true se houve sobreposição, false se os intervalos não se encontram em ponto nenhum.
Repare no parâmetro de saída: até agora você devolveu números por referência. Aqui o que volta é uma struct inteira, e o mecanismo é o mesmo — referência funciona com qualquer tipo, inclusive os que você mesmo criou.
A interseção começa no maior dos dois inícios e termina no menor dos dois fins. Se essa conta produzir um início maior que o fim, é porque os intervalos não se sobrepõem — devolva false e não mexa no parâmetro de saída. Dois intervalos que se tocam em um ponto só (um termina exatamente onde o outro começa) contam como sobreposição, de duração zero.
Resolva com comparações escritas na mão (if ou operador ternário) — std::max e std::min moram em <algorithm>, que é assunto do capítulo 8.
Intervalo aula{8.0, 10.0};
Intervalo reuniao{9.0, 11.0};
Intervalo r;
intersecao(aula, reuniao, r) // -> true, e r vale {9.0, 10.0}
Intervalo tarde{14.0, 16.0};
intersecao(aula, tarde, r) // -> false
// ex07 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <cmath>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX07_H
#define EX07_H
struct Intervalo {
double inicio;
double fim;
};
// Escreve em "resultado" a parte em que os dois intervalos se sobrepoem.
// Devolve true se ha sobreposicao; devolve false e nao mexe em "resultado"
// se eles nao se sobrepoem em ponto nenhum.
bool intersecao(const Intervalo& a, const Intervalo& b, Intervalo& resultado);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
bool intersecao(const Intervalo& a, const Intervalo& b, Intervalo& resultado) {
// TODO: o inicio da intersecao e o MAIOR entre a.inicio e b.inicio;
// o fim e o MENOR entre a.fim e b.fim.
// Se o inicio calculado for maior que o fim, nao ha sobreposicao:
// devolva false. Caso contrario, escreva o Intervalo em "resultado"
// e devolva true.
return false;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
Intervalo r{0.0, 0.0};
// sobreposicao parcial
assert(intersecao(Intervalo{8.0, 10.0}, Intervalo{9.0, 11.0}, r));
assert(std::abs(r.inicio - 9.0) <= 0.0001);
assert(std::abs(r.fim - 10.0) <= 0.0001);
// a ordem dos argumentos nao muda o resultado
assert(intersecao(Intervalo{9.0, 11.0}, Intervalo{8.0, 10.0}, r));
assert(std::abs(r.inicio - 9.0) <= 0.0001);
assert(std::abs(r.fim - 10.0) <= 0.0001);
// um intervalo inteiramente dentro do outro
assert(intersecao(Intervalo{0.0, 24.0}, Intervalo{8.0, 10.0}, r));
assert(std::abs(r.inicio - 8.0) <= 0.0001);
assert(std::abs(r.fim - 10.0) <= 0.0001);
// sem sobreposicao nenhuma: devolve false e nao mexe no resultado
r = Intervalo{-1.0, -1.0};
assert(!intersecao(Intervalo{8.0, 10.0}, Intervalo{14.0, 16.0}, r));
assert(std::abs(r.inicio + 1.0) <= 0.0001);
assert(!intersecao(Intervalo{14.0, 16.0}, Intervalo{8.0, 10.0}, r));
// tocam em um ponto so: conta, com duracao zero
assert(intersecao(Intervalo{8.0, 10.0}, Intervalo{10.0, 12.0}, r));
assert(std::abs(r.inicio - 10.0) <= 0.0001);
assert(std::abs(r.fim - 10.0) <= 0.0001);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex08¶
Dados o enum class Prioridade { Baixa, Media, Alta } e a struct Tarefa (campos titulo, prioridade e minutos, já declarados), escreva minutos_reservados, que devolve quanto tempo separar para a tarefa, segundo a prioridade:
Alta→ o dobro deminutos;Media→ exatamenteminutos;Baixa→ a metade deminutos(divisão inteira: 45 vira 22).
Use um switch sobre t.prioridade. O erro que quase todo mundo comete na primeira tentativa é escrever case Alta: — com enum class, o nome mora dentro do tipo, então é case Prioridade::Alta:.
minutos_reservados(Tarefa{"entregar relatorio", Prioridade::Alta, 30}) // -> 60
minutos_reservados(Tarefa{"responder e-mails", Prioridade::Media, 30}) // -> 30
minutos_reservados(Tarefa{"organizar mesa", Prioridade::Baixa, 45}) // -> 22
// ex08 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX08_H
#define EX08_H
enum class Prioridade { Baixa, Media, Alta };
struct Tarefa {
std::string titulo;
Prioridade prioridade;
int minutos;
};
// Retorna quantos minutos reservar para a tarefa:
// Alta = o dobro de minutos, Media = minutos, Baixa = metade (divisao inteira).
int minutos_reservados(const Tarefa& t);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
int minutos_reservados(const Tarefa& t) {
// TODO: use um switch sobre t.prioridade.
// Lembre do qualificador: e "case Prioridade::Alta:", nao "case Alta:".
return 0;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(minutos_reservados(Tarefa{"entregar relatorio", Prioridade::Alta, 30}) == 60);
assert(minutos_reservados(Tarefa{"responder e-mails", Prioridade::Media, 30}) == 30);
assert(minutos_reservados(Tarefa{"organizar mesa", Prioridade::Baixa, 45}) == 22);
// metade de um numero par, e os casos de borda com zero
assert(minutos_reservados(Tarefa{"alongar", Prioridade::Baixa, 10}) == 5);
assert(minutos_reservados(Tarefa{"nada", Prioridade::Alta, 0}) == 0);
assert(minutos_reservados(Tarefa{"nada", Prioridade::Baixa, 1}) == 0);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex09¶
Escreva primeiro_repetido, que recebe um texto e escreve num parâmetro por referência o primeiro caractere que já tinha aparecido antes nele. A função devolve bool: true se encontrou uma repetição, false se todos os caracteres forem distintos.
Atenção ao que "primeiro" significa aqui: é o primeiro caractere que, ao ser lido da esquerda para a direita, já tinha sido visto. Em "programacao", o r da posição 4 é a primeira repetição, mesmo que o o apareça mais vezes no total.
Repare que o que volta é o caractere, e não a posição. Quando a resposta natural da pergunta é o próprio valor, não há motivo para devolver o índice e obrigar quem chamou a ir buscar o caractere de volta. E repare por que aqui não serve um valor especial como o -1 do ex06: qualquer char é uma resposta possível, então não sobra nenhum valor para significar "não achei" — é por isso que esta função devolve bool à parte.
char c;
primeiro_repetido("programacao", c) // -> true, e c vale 'r'
primeiro_repetido("bola", c) // -> false
primeiro_repetido("", c) // -> false
// ex09 — versao de arquivo unico (gerada automaticamente,
// nao edite este arquivo direto: edite os fontes em exercicios/ e rode
// tools/gerar_single.py --todos de novo).
//
// Cole este arquivo inteiro no seu compilador online e rode.
#include <cassert>
#include <iostream>
#include <string>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX09_H
#define EX09_H
// Escreve em "repetido" o primeiro caractere de "texto" que ja havia
// aparecido antes. Devolve true se encontrou repeticao; devolve false e nao
// mexe em "repetido" se todos os caracteres forem distintos.
bool primeiro_repetido(const std::string& texto, char& repetido);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
bool primeiro_repetido(const std::string& texto, char& repetido) {
// TODO: para cada posicao i, verifique se texto[i] ja apareceu
// em alguma posicao anterior (um laco de j = 0 ate i).
// Se ja apareceu, escreva texto[i] em "repetido" e devolva true.
// Se o laco terminar, devolva false.
return false;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
char c = '?';
assert(primeiro_repetido("programacao", c));
assert(c == 'r');
// todos distintos: devolve false e nao mexe no parametro de saida
c = '?';
assert(!primeiro_repetido("bola", c));
assert(c == '?');
// texto vazio e texto de um caractere so
assert(!primeiro_repetido("", c));
assert(!primeiro_repetido("a", c));
// repeticao logo no comeco
assert(primeiro_repetido("aa", c));
assert(c == 'a');
// a primeira repeticao nao e a do caractere mais frequente
assert(primeiro_repetido("abcbb", c));
assert(c == 'b');
std::cout << "Todos os testes passaram!\n";
return 0;
}