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
, e . - 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:
, , . - 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
, , 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
. Dentro da função uso o operador de desreferência para escrever nesses endereços, por ex.: . - 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:
-
, , — 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:
- Comparar
, , para descobrir qual é o maior. - Depois, entre os outros dois valores (os que não são o maior), escolher o maior — esse será a segunda maior nota.
- Escrever os resultados via ponteiros:
e .
Passo 4
Vamos ilustrar o método com um exemplo numérico (para ficar concreto). Suponha
,
,
.
- Primeiro: comparo
com e . Vejo que é o maior ( ). - Segundo: entre
e (os que restaram), o maior é . - Resultado: maiores são
e , nessa ordem.
Agora, generalizando em forma de decisão:
- Se
e , então é o maior. A segunda maior é . - Senão, se
e , então é o maior. A segunda maior é . - Senão (resta o caso),
é o maior. A segunda maior é .
Observações sobre igualdades:
- Usei
(maior ou igual) para lidar bem com empates. Se houver empates, por exemplo 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);
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 entren2en3. - Em seguida usamos
else ifpara o cason2ser maior ou igual aos outros. - Finalmente o
elseassume quen3é 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 < btrocar; depois comparara < ctrocar; enfim, ao finalaebseriam 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
*melhor1e 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;
}
}
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;
}
}