Lista 02 · Funções: valor, ponteiro e referência¶
Exercícios da Semana 2 — Funções: valor, ponteiro e referência. Muitos exercícios aqui pedem uma função que altera o argumento do chamador — é assim que o próprio harness de teste consegue checar se sua função usou referência corretamente: ele chama sua função e depois lê a variável que passou.
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¶
Escreva dobra_valor, que recebe um int por referência e dobra o valor da variável do chamador (a função não retorna nada — void).
// 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>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX01_H
#define EX01_H
// Dobra o valor de x, alterando a variavel do chamador (passagem por referencia).
void dobra_valor(int& x);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
void dobra_valor(int& x) {
// TODO: dobre o valor de x (ex: x = x * 2;)
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
int a = 5;
dobra_valor(a);
assert(a == 10);
int b = 0;
dobra_valor(b);
assert(b == 0);
int c = -3;
dobra_valor(c);
assert(c == -6);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex02¶
Escreva troca, que recebe dois int por referência e troca os valores entre si (o clássico swap).
// 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>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX02_H
#define EX02_H
// Troca os valores de a e b entre si.
void troca(int& a, int& b);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
void troca(int& a, int& b) {
// TODO: troque os valores de a e b (voce vai precisar de uma variavel auxiliar).
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
int a = 1, b = 2;
troca(a, b);
assert(a == 2);
assert(b == 1);
int c = -5, d = 5;
troca(c, d);
assert(c == 5);
assert(d == -5);
int e = 7, f = 7;
troca(e, f);
assert(e == 7);
assert(f == 7);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex03¶
Escreva potencia, que recebe uma base (double) e um expoente (int), e devolve a base elevada ao expoente. O expoente deve ter valor padrão 2 — ou seja, potencia(3.0) calcula o quadrado de 3.
Escreva a multiplicação na mão, com um for: comece o resultado em 1.0 e multiplique pela base tantas vezes quantas o expoente mandar. Nada de std::pow; o assunto aqui é o parâmetro com valor padrão, e a conta precisa ser sua para você ver os dois casos de borda.
E são três casos, não um:
- expoente
0— o laço não roda nenhuma vez e o resultado fica em1.0, que é a resposta certa. Se você começar o resultado na base em vez de em1.0, este caso quebra. - expoente negativo —
potencia(2.0, -2)é1 / potencia(2.0, 2), ou seja,0.25. Calcule com o expoente positivo e inverta no fim. - base negativa — sai de graça, desde que você multiplique de verdade:
potencia(-3.0, 3)é-27.
Lembre que o valor padrão vai no .h, na declaração, e não na definição em .cpp — repetir o = 2 nos dois lugares é erro de compilação.
potencia(3.0) // -> 9.0 (usa o expoente padrao 2)
potencia(2.0, 10) // -> 1024.0
potencia(5.0, 0) // -> 1.0
potencia(2.0, -2) // -> 0.25
// 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 <cmath>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX03_H
#define EX03_H
// Retorna base elevada a expoente. Se o expoente nao for informado, usa 2.
// Expoente negativo devolve o inverso: potencia(2.0, -2) == 0.25.
double potencia(double base, int expoente = 2);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
double potencia(double base, int expoente) { // sem o "= 2" aqui: ele fica no .h
// TODO: guarde se o expoente e negativo e trabalhe com ele positivo.
// Comece resultado em 1.0 e multiplique por base uma vez para cada
// unidade do expoente. Se o expoente era negativo, devolva 1.0 / resultado.
return 0.0;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
static bool perto(double a, double b) {
return std::fabs(a - b) < 0.0001;
}
int main() {
// sem informar o expoente: usa o padrao 2
assert(perto(potencia(3.0), 9.0));
assert(perto(potencia(1.5), 2.25));
// expoente informado
assert(perto(potencia(2.0, 10), 1024.0));
assert(perto(potencia(10.0, 3), 1000.0));
// expoente 1 e expoente 0
assert(perto(potencia(7.0, 1), 7.0));
assert(perto(potencia(5.0, 0), 1.0));
assert(perto(potencia(0.0, 0), 1.0));
// expoente negativo
assert(perto(potencia(2.0, -2), 0.25));
assert(perto(potencia(4.0, -1), 0.25));
// base negativa: o sinal sai da propria multiplicacao
assert(perto(potencia(-3.0, 3), -27.0));
assert(perto(potencia(-3.0), 9.0));
// base zero com expoente positivo
assert(perto(potencia(0.0, 5), 0.0));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex04¶
Implemente duas versões sobrecarregadas de dobro: uma para int e outra para double, cada uma devolvendo o dobro do valor recebido, mantendo o tipo.
// 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 <cmath>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX04_H
#define EX04_H
// Duas versoes sobrecarregadas: cada uma retorna o dobro do valor recebido.
int dobro(int x);
double dobro(double x);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
int dobro(int x) {
// TODO: retorne o dobro de x (versao int).
return 0;
}
double dobro(double x) {
// TODO: retorne o dobro de x (versao double).
return 0.0;
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(dobro(5) == 10);
assert(dobro(0) == 0);
assert(dobro(-3) == -6);
assert(std::abs((dobro(2.5)) - (5.0)) <= (0.0001));
assert(std::abs((dobro(0.0)) - (0.0)) <= (0.0001));
assert(std::abs((dobro(-1.5)) - (-3.0)) <= (0.0001));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex05¶
Escreva maiusculo, que recebe um std::string por referência e converte todas as letras para maiúsculas, alterando a própria string do chamador (void, sem retorno).
// 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
// Converte texto para maiusculas, alterando a propria string do chamador.
void maiusculo(std::string& texto);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
void maiusculo(std::string& texto) {
// TODO: percorra "texto" convertendo cada caractere para maiusculo
// (dica: <cctype> tem a funcao std::toupper).
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
std::string a = "ola mundo";
maiusculo(a);
assert(a == std::string("OLA MUNDO"));
std::string b = "Ja Maiusculo";
maiusculo(b);
assert(b == std::string("JA MAIUSCULO"));
std::string c = "";
maiusculo(c);
assert(c == std::string(""));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex06¶
Escreva repete, que recebe um texto (const std::string& — sem copiar, sem alterar) e um número de vezes, e devolve o texto repetido essa quantidade de vezes.
// 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 "texto" repetido "vezes" vezes.
std::string repete(const std::string& texto, int vezes);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
std::string repete(const std::string& texto, int vezes) {
// TODO: monte uma string com "texto" concatenado "vezes" vezes.
return "";
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
assert(repete("ab", 3) == std::string("ababab"));
assert(repete("x", 0) == std::string(""));
assert(repete("oi", 1) == std::string("oi"));
assert(repete("", 5) == std::string(""));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex07¶
Escreva ajusta_valor, que recebe dois ponteiros para int: ela deve incrementar em 1 o valor apontado pelo primeiro e decrementar em 1 o valor apontado pelo segundo. Não retorna nada.
Repare que aqui o exercício pede ponteiro (int*), e não referência (int&): quem chama precisa escrever ajusta_valor(&a, &b), e dentro da função você usa *a para chegar ao valor.
// 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>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX07_H
#define EX07_H
// Incrementa o valor apontado por sobe e decrementa o valor apontado por desce.
void ajusta_valor(int* sobe, int* desce);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
void ajusta_valor(int* sobe, int* desce) {
// TODO: some 1 ao valor apontado por sobe e subtraia 1 do valor
// apontado por desce (lembre do * antes do nome do ponteiro).
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
int a = 10, b = 10;
ajusta_valor(&a, &b);
assert(a == 11);
assert(b == 9);
int c = 0, d = 0;
ajusta_valor(&c, &d);
assert(c == 1);
assert(d == -1);
int e = -5, f = -5;
ajusta_valor(&e, &f);
assert(e == -4);
assert(f == -6);
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex08¶
Escreva raiz_quadrada, que recebe um double e um ponteiro para double onde o resultado deve ser guardado. A função calcula a raiz quadrada do número (std::sqrt, de <cmath>) e escreve o valor no endereço apontado.
Se o número for negativo, não existe raiz quadrada real: guarde -1.0 no resultado para sinalizar isso.
Este é o padrão clássico de "devolver resultado pelo parâmetro", e ele volta várias vezes no curso: sempre que uma função pode não ter resposta, ela devolve bool (ou um valor especial como -1) e entrega o resultado por um parâmetro.
// 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 <cmath>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX08_H
#define EX08_H
// Calcula a raiz quadrada de numero e guarda no endereco apontado por resultado.
// Se numero for negativo, guarda -1.0 (nao ha raiz quadrada real).
void raiz_quadrada(double numero, double* resultado);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
void raiz_quadrada(double numero, double* resultado) {
// TODO: se numero for negativo, guarde -1.0 em *resultado.
// Caso contrario, guarde std::sqrt(numero).
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
double r = 0.0;
raiz_quadrada(9.0, &r);
assert(std::abs((r) - (3.0)) <= (0.0001));
raiz_quadrada(0.0, &r);
assert(std::abs((r) - (0.0)) <= (0.0001));
raiz_quadrada(2.0, &r);
assert(std::abs((r) - (1.41421356)) <= (0.0001));
raiz_quadrada(-4.0, &r);
assert(std::abs((r) - (-1.0)) <= (0.0001));
std::cout << "Todos os testes passaram!\n";
return 0;
}
ex09¶
Escreva divide, que recebe dois inteiros e devolve os dois resultados da divisão inteira — quociente e resto — pelos parâmetros de referência. A função não retorna nada.
É a resposta desta semana para "e se eu precisar devolver mais de uma coisa?". Na Lista 03 você vai ver a outra, com std::pair.
// 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>
// ============================================================
// Declaracoes do exercicio
// ============================================================
#ifndef EX09_H
#define EX09_H
// Calcula a divisao inteira de a por b, devolvendo os DOIS resultados
// pelos parametros de referencia. Assume b diferente de zero.
void divide(int a, int b, int& quociente, int& resto);
#endif
// ============================================================
// ESCREVA SUA SOLUCAO AQUI
// ============================================================
void divide(int a, int b, int& quociente, int& resto) {
// TODO: quociente recebe a / b, resto recebe a % b.
// Como sao referencias, atribuir aqui altera as variaveis do chamador.
}
// ============================================================
// NAO ALTERE — testes
// ============================================================
int main() {
int q = 0, r = 0;
divide(17, 5, q, r);
assert(q == 3);
assert(r == 2);
divide(20, 4, q, r);
assert(q == 5);
assert(r == 0);
divide(3, 10, q, r);
assert(q == 0);
assert(r == 3);
std::cout << "Todos os testes passaram!\n";
return 0;
}