Desenvolva uma função/procedimento denominada duas_maiores_notas() a qual deverá receber três notas (valores do tipo float) e retorne as duas melhores notas. O retorno dessas das duas melhores notas deve ser feito de maneira indireta, isto é, utilizando ponteiros.

Passo 1

O enunciado pede uma rotina chamada duas_maiores_notas() que:
  • recebe três notas (valores do tipo float). Vamos chamar essas entradas de n_1, n_2 e n_3.
  • deve “retornar” as duas melhores notas, mas o retorno precisa ser indireto — isto é, usando ponteiros (endereços) para colocar as duas melhores notas em variáveis fornecidas pelo chamador.
  • não especifica explicitamente a ordem das duas notas retornadas; vou assumir (e explicar por que) que retornaremos a maior primeiro e a segunda maior em seguida (ordem decrescente: maior → menor).
Informações entregues pelo enunciado:
  • Três números em ponto flutuante: n_1, n_2, n_3.
  • Requisito de retorno indireto via ponteiros (ou seja, parâmetros do tipo ponteiro onde colocaremos as duas melhores notas).
Pergunta que o enunciado faz:
  • Como implementar a função/procedimento que recebe n_1, n_2, n_3 e preenche, por ponteiros, as duas maiores notas (maior primeiro)?

Passo 2

O que significa “retornar via ponteiros” (retorno indireto)? Vou explicar com calma, como um amigo:
  • Em C, uma função só pode retornar um valor diretamente (salvo retornar uma struct). Mas frequentemente queremos que a função preencha mais de uma informação de saída. Uma forma clássica é pedir ao chamador que passe o endereço (ponteiro) de variáveis onde a função vai escrever os resultados.
  • Exemplo: se eu quero que a função escreva duas floats no chamador, eu declaro parâmetros do tipo float *. Dentro da função uso o operador de desreferência * para escrever nesses endereços, por ex.: *saida = valor;.
  • Assim a assinatura que usaremos é uma rotina que não retorna valor (tipo void) e recebe três floats e dois ponteiros para float onde colocaremos as duas maiores notas.
Explicando a assinatura proposta (sem código ainda): a função terá parâmetros:
  • n_1, n_2, n_3 — entradas (os três valores).
  • ponteiro para onde escrever a maior nota (vou chamar de melhor1).
  • ponteiro para onde escrever a segunda maior nota (vou chamar de melhor2).

Passo 3

Escolha do método para achar as duas maiores notas (por que esse método?)
Opções possíveis:
  • Ordenar os três valores (por exemplo, fazer pequenas trocas) e pegar os dois maiores. Simples e robusto.
  • Encontrar o maior e, depois, entre os dois restantes achar o segundo maior. Também simples e ligeiramente mais eficiente (menos trocas/atribuições).
Vou usar o método “achar o maior primeiro e depois o segundo entre os dois restantes” porque é claro, usa poucas comparações e é fácil de implementar sem estruturas extras — perfeito para prova e sem necessidade de biblioteca.
Passos lógicos do método:
  1. Comparar n_1, n_2, n_3 para descobrir qual é o maior.
  2. Depois, entre os outros dois valores (os que não são o maior), escolher o maior — esse será a segunda maior nota.
  3. Escrever os resultados via ponteiros: *melhor1 = \text{maior} e *melhor2 = \text{segunda\_maior}.

Passo 4

Vamos ilustrar o método com um exemplo numérico (para ficar concreto). Suponha n_1=5{,}0, n_2=7{,}5, n_3=6{,}0.
  • Primeiro: comparo n_1 com n_2 e n_3. Vejo que n_2 é o maior ( 7{,}5).
  • Segundo: entre n_1 e n_3 (os que restaram), o maior é n_3=6{,}0.
  • Resultado: maiores são 7{,}5 e 6{,}0, nessa ordem.
Agora, generalizando em forma de decisão:
  • Se n_1 \ge n_2 e n_1 \ge n_3, então n_1 é o maior. A segunda maior é \max(n_2, n_3).
  • Senão, se n_2 \ge n_1 e n_2 \ge n_3, então n_2 é o maior. A segunda maior é \max(n_1, n_3).
  • Senão (resta o caso), n_3 é o maior. A segunda maior é \max(n_1, n_2).
Observações sobre igualdades:
  • Usei \ge (maior ou igual) para lidar bem com empates. Se houver empates, por exemplo n_1 = n_2 e ambos são máximos, nosso critério ainda funciona e a segunda maior será o outro valor máximo.

Passo 5

Agora transformando a ideia em código C (explicando linha a linha). A assinatura que sugeri é:
void duas_maiores_notas(float n1, float n2, float n3, float *melhor1, float *melhor2);
Explicação dos parâmetros:
  • n1, n2, n3 — entrada (as três notas).
  • *melhor1 — endereço onde escrever a maior nota (maior primeiro).
  • *melhor2 — endereço onde escrever a segunda maior nota.
Corpo (explicando cada bloco):
  • Primeiro checamos se n1 é maior ou igual aos outros: if (n1 >= n2 && n1 >= n3) — aí n1 é a maior. Em seguida *melhor1 = n1; e *melhor2 = (n2 >= n3) ? n2 : n3; para escolher entre n2 e n3.
  • Em seguida usamos else if para o caso n2 ser maior ou igual aos outros.
  • Finalmente o else assume que n3 é maior (ou empatado como maior).
Uso do operador ternário ?: é apenas sintaxe compacta para escolher o maior entre dois valores; se preferir, pode usar if normal — em prova às vezes é mais claro escrever com if.

Passo 6

Código comentado (explicando com calma como seria — aqui descrevo o que estará no código final):
  • Declaramos a função com void (não retorna valor diretamente).
  • Fazemos comparações seguindo o plano do Passo 4.
  • Escrevemos as duas saídas via desreferência dos ponteiros.
Vou explicar também a alternativa (ordenar por troca):
  • Outra estratégia é colocar os três valores em variáveis locais e fazer trocas para garantir ordem decrescente: por exemplo, se a < b trocar; depois comparar a < c trocar; enfim, ao final a e b seriam os dois maiores. Isso é igualmente válido, só que faz trocas de valores. O método do “maior + max dos dois restantes” usa menos passos mentais e fica mais direto para prova.

Passo 7

Exemplo de uso (para você entender como chamar a função na prática):
  • No chamador (por exemplo no main), você declara:
    float n1 = 5.0f, n2 = 7.5f, n3 = 6.0f;
    float m1, m2;
    duas_maiores_notas(n1, n2, n3, &m1, &m2);
    // agora m1 tem a maior e m2 a segunda maior.
Explicando: &m1 passa o endereço de m1 para a função. Dentro da função, quando ela fizer *melhor1 = ..., o valor será escrito na variável m1 do chamador.

Passo 8

Casos de borda e observações finais:
  • Empates: se duas ou três notas forem iguais, o critério com >= resolve ok; por exemplo, se todas iguais, as duas maiores serão esse mesmo valor.
  • Valores especiais (NaN, infinitos): não entrei nesses detalhes — normalmente em provas básicas não exigem tratar NaN. Se for necessário, trate com funções de biblioteca ou checagens explícitas.
  • Ordem: a função que propus devolve a maior em *melhor1 e a segunda maior em *melhor2. Se preferir ordem ascendente, basta inverter a escrita.
Força! Você consegue — a ideia é simples e fácil de escrever na prova. Abaixo, na seção final, deixo apenas a função pronta (pronta para copiar/colar em C).

Resposta

void duas_maiores_notas(float n1, float n2, float n3, float *melhor1, float *melhor2) {
if (n1 >= n2 && n1 >= n3) {
*melhor1 = n1;
*melhor2 = (n2 >= n3) ? n2 : n3;
} else if (n2 >= n1 && n2 >= n3) {
*melhor1 = n2;
*melhor2 = (n1 >= n3) ? n1 : n3;
} else {
*melhor1 = n3;
*melhor2 = (n1 >= n2) ? n1 : n2;
}
}

Exercícios relacionados