Solicitação de algoritmo 4

Solicitação recebida de Caio da Silva Caetano. O problema encontrado no código dele é que a execução do código não gerava a média correta. Segue o enunciado e o código enviado.

Enunciado: fazer um programa para obter o nome e as 2 notas dos 28 alunos de uma turma. As notas serão informadas pelo professor. O programa deve calcular a média das 2 notas de cada aluno e exibir “Aprovado” caso a média seja igual ou superior a 7.0 e reprovado, caso contrário. Armazenar os valores em variável vetorial.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char vetor [3][3][28];
int main(void) {
    float nota1;
    float nota2;
    float media;
    int i,j;
    char nome[28];
    for(i=0;i<3;i++){
        printf("\nEntre com o nome do aluno: ");
        fflush(stdin);
        gets(vetor[i][0]);
        for(j=1;j<3;j++){
            printf("Informe a %da. nota:",j);
            fflush(stdin);
            gets(vetor[i][j]);
        }
    }
    for(i=0;i<3;i++){
        nota1=atof(vetor[i][1]);nota2=atof(vetor[i][2]);;
        media = (nota1 + nota2 ) / 2;
        printf("\nMedia final = %.2f", media);
        if (media >= 7.0)
            printf(" ( aluno %s aprovado ).",vetor[i][0]);
        else if ((media >= 4.0) && (media < 7.0))
            printf(" ( aluno %s em recuperacao ).",vetor[i][0]);
        else
            printf(" ( aluno %s reprovado ).",vetor[i][0]);
    }
    getch();
}

O código enviado mostra que foi pensado em utilizar uma matriz tridimensional para armazenar os alunos e suas notas. Como a matriz somente pode ser de um tipo e ela armazena dados numéricos e alfanuméricos, foi decidido corretamente em criar uma matriz de caracteres. Obviamente, ao armazenar os números nela, foi necessário fazer a conversão deles posteriormente para os cálculos.

Aqui vem uma primeira recomendação. A matriz criada é 3x3x28 e fica óbvio que uma dimensão de tamanho 3 é para guardar as 2 notas e o nome do aluno, outra dimensão de tamanho 3 é porque o algoritmo cumpre o enunciado apenas para 3 alunos (e não 28 como é pedido) e a dimensão de tamanho 28 se refere ao tamanho máximo do nome do aluno. Veja que esse tamanho 28 se confunde com o número de alunos do enunciado e por isso eu colocaria outro valor (eu coloquei o tamanho 30 no meu código). Também recomendo especificar o número de alunos como uma constante, para depois alterar somente o valor da constante e ter o meu código funcionando para 3 alunos durante os testes e 28 alunos para a conclusão do algoritmo.

Outra coisa é o uso da função gets(). É comum os compiladores mostrarem um warning ao utilizar essa função. Isso porque, se for informado um nome maior do que o definido (no caso, um nome com mais de 27 letras – isso porque o último caractere de uma string deve ser o ‘\0’), isso gerará um overflow do buffer (estouro de buffer). Uma função alternativa e que previne essa possibilidade de falha é a função fgets(). Muitos usam a função gets() porque aparece em material mais antigo sobre a linguagem C e também porque precisa receber apenas de um parâmetro (no caso, a variável a ser lida), mas a fgets() não é tão mais difícil de utilizar.

Para a função fgets(), informe a variável string a ser lida, o tamanho da string a ser lida e, considerando a entrada padrão (normalmente o teclado), o parâmetro stdin. No código do caso ficará fgets(vetor[i][0], 29, stdin). Lembrando que o tamanho 29 é porque o tamanho da variável para o nome está em é 30, mas é preciso deixar um caractere para receber o ‘\0’.

Veja que eu inicialmente fiz recomendações de melhorias. Agora vamos falar sobre o erro. Veja que no código foi corretamente utilizada a função atof() para converter a string no número.

Alterando o código para funcionar com a constante e a função fgets() teremos pouca diferença do anterior, mas ele segue a seguir. Eu também tirei a variável de nome vetor do escopo global e coloquei no escopo local porque não faz sentido ela no escopo global.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define ALUNOS 3

int main(void) {
    float nota1;
    float nota2;
    float media;
    char vetor [ALUNOS][3][30];
    int i,j;
    //char nome[30];  --remover porque não é utilizada
    for(i=0;i<ALUNOS;i++){
        printf("\nEntre com o nome do aluno: ");
        fflush(stdin);
        fgets(vetor[i][0],29,stdin);
        for(j=1;j<3;j++){
            printf("Informe a %da. nota:",j);
            fflush(stdin);
            fgets(vetor[i][j],5,stdin); //pensando na entrada 09.55
        }
    }
    for(i=0;i<ALUNOS;i++){
        nota1=atof(vetor[i][1]);
        nota2=atof(vetor[i][2]);;
        media = (nota1 + nota2 ) / 2;
        printf("\nMedia final = %.2f", media);
        if (media >= 7.0)
            printf(" ( aluno %s aprovado ).",vetor[i][0]);
        else
            printf(" ( aluno %s reprovado ).",vetor[i][0]);
    }
    return 0;
}

Teste o código em: https://ideone.com/yFRf93

Particularmente eu não teria utilizado a solução com a matriz tridimensional e sim com uma matriz para notas e outra para os nomes. Isso porque a estrutura tridimensional vai ser subutilizada. Para cada nota serão alocados 30 caracteres, sendo que 6 seria o máximo possível para elas. Além disso é preciso fazer a conversão de string para número o que, embora seja somente usar uma função, possui custo computacional associado. O código abaixo mostra essa opção de codificação.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#define ALUNOS 3
 
int main(void) {
    float notas[ALUNOS][2], media;
    char  nomes[ALUNOS][30];
    int i,j;
    for(i=0;i<ALUNOS;i++){
        printf("\nEntre com o nome do aluno: ");
        fgets(nomes[i],29,stdin);
        for(j=0;j<2;j++){
            printf("Informe a %da. nota:", j);
            scanf("%f ", &notas[i][j]);
        }
    }
    for(i=0;i<ALUNOS;i++){
        media = (notas[i][0] + notas[i][1]) / 2;
        printf("\nMedia final = %.2f", media);
        if (media >= 7.0)
            printf(" ( aluno %s aprovado ).",nomes[i]);
        else
            printf(" ( aluno %s reprovado ).",nomes[i]);
    }
    return 0;
}

Teste o código em: https://ideone.com/wdsXif

Complementando a solução proposta, segue a solução utilizando funções. Elaborei 3 funções para a solução, sendo uma para ler os dados, outra para calcular a média de cada aluno e uma terceira para mostrar se aluno está aprovado ou reprovado.

A função leituraDados() é um copia e cola de um trecho da função main(). Essa função e a mostraAprovacao() são funções que precisam receber as duas matrizes.

A função calcularMedias() somente precisa receber a matriz com as notas. Veja que para as médias foi necessário aumentar uma coluna na matriz de notas. Isso porque a matriz agora armazena as duas notas do aluno e a média das notas. Poderia ter feito o cálculo das médias na função mostraAprovacao(), dispensando inclusive a coluna adicional na matriz de notas, mas preferi dessa forma para facilitar o entendimento de todo o código (foi uma decisão pessoal e também achei didático mostrar que a função calcularMedias() precisa de menos parâmetros do que as demais).

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
     
#define ALUNOS 3
    
void leituraDados(char nomes[ALUNOS][30], float notas[ALUNOS][3]) {
    int i,j;
    for(i=0;i<ALUNOS;i++){
        printf("\nEntre com o nome do aluno: ");
        fgets(nomes[i],29,stdin);
        for(j=0;j<2;j++){
            printf("Informe a %da. nota:", j);
            scanf("%f ", &notas[i][j]);
        }
    }
}        

void calcularMedias(float notas[ALUNOS][3]) {
    int i;
    for(i=0;i<ALUNOS;i++){
        notas[i][2] = (notas[i][0] + notas[i][1]) / 2;
    }
}
    
void mostraAprovacao(char nomes[ALUNOS][30], float notas[ALUNOS][3]) {
    int i;
    for(i=0;i<ALUNOS;i++){
        printf("\nMedia final = %.2f", notas[i][2]);
        if (notas[i][2] >= 7.0)
            printf(" ( aluno %s aprovado ).",nomes[i]);
        else
            printf(" ( aluno %s reprovado ).",nomes[i]);
    }
}
    
int main(void) {
    float notas[ALUNOS][3], media;
    char  nomes[ALUNOS][30];
    
    leituraDados(nomes, notas);
    calcularMedias(notas);
    mostraAprovacao(nomes, notas);

    return 0;
}

Gosto sempre de destacar a vantagem na legibilidade do código que o uso de funções traz. Olhando para a função main(), fica claro ler o que o algoritmo faz.

Teste o código em: https://ideone.com/e6Se8c

Share

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.