Lista de exercícios 06

Assuntos novos: modularização e funções.

Resumo e exemplos:

A modularização é uma técnica de programação usada para dividir um programa em partes menores, organizando-as de acordo com suas funcionalidades.

Existem muitos benefícios:

  • Permite testar e achar erros mais facilmente: concentra-se o teste em cada parte separadamente.
  • Evita a repetição de código: trechos de código repetitivos podem ser escritos uma única vez.
  • Aumenta a reutilização: fácil de reusar partes no próprio programa ou em outro programa.
  • Aumenta o nível de alterabilidade do programa: basta alterar uma vez já que a parte alterada já é reutilizada em outros lugares.
  • Aumenta a legibilidade do programa: principalmente o programa principal fica mais fácil de ser lido.
  • Permite a contrução de abstrações sobre os problemas.

Essas partes, ou módulos, na Linguagem C, são chamadas de funções.

A Linguagem C possui uma biblioteca grande de funções já prontas. Algumas delas já usamos nas aulas:

printf, scanf, srand, rand, gets, fflush etc.

Motivação:
Observe o exemplo a seguir: existem muitas repetições de código além do tamanho excessivo da função main.
Depois, mas adiante, observe a outra versão que resolve o mesmo problema: as funções deixam o programa principal (main) mais limpo e fácil de ser entendido.

Problema:
Deseja-se armazenar, de uma turma composta de 30 alunos, o nome e a média de cada aluno. Para isso serão informados o nome, a nota da primeira prova, a nota da segunda prova e os pontos extras de participação de cada aluno. A média deve ser calculada sobre as duas primeiras notas. Os pontos de participação serão somados na média final mas sempre obedecendo o limite máximo de 10 para a média.
Após a entrada de dados deve-se exibir a relação de alunos com os seus nomes e médias.

// Versão 1
#include <stdio.h> 
#include <stdlib.h> 
 
#define MAX_ALUNOS 30 
 
struct TipoAluno { 
      char nome[50]; 
      float media; 
}; 
 
int main() { 
      struct TipoAluno alunos[MAX_ALUNOS]; 
      float nota1, nota2, pontos; 
      int i; 
      for(i=0; i < MAX_ALUNOS; i++) { 
            printf("\nEntre com o nome do aluno: "); 
            fflush(stdin);
            gets(alunos[i].nome); 
            printf("Entre com a primeira nota (0 a 10): "); 
            do { 
                  scanf("%f", &nota1); 
                  if(nota1 < 0 || nota1 > 10) { 
                        printf("Erro, valor deve ser de 0 a 10 \n"); 
                  } 
            }while(nota1 < 0 || nota1 > 10);   
            printf("Entre com a segunda nota (0 a 10): "); 
            do { 
                  scanf("%f", &nota2); 
                  if(nota2 < 0 || nota2 > 10) { 
                        printf("Erro, valor deve ser de 0 a 10 \n"); 
                  } 
            }while(nota2 < 0 || nota2 > 10);   
            printf("Entre com os pontos (0 a 10): "); 
            do { 
                  scanf("%f", &pontos); 
                  if(pontos < 0 || pontos > 10) { 
                        printf("Erro, valor deve ser de 0 a 10 \n"); 
                  } 
            }while(pontos < 0 || pontos > 10);   
 
            float media = (nota1 + nota2)/2 + pontos; 
            // não permite que a media seja maior 10 
            if(media > 10) 
                media = 10; 
 
            alunos[i].media = media; 
      } 
      printf("\n\nExibicao dos dados:"); 
      for(i=0; i < MAX_ALUNOS; i++) {   
            printf("\n\nAluno: %s", alunos[i].nome); 
            printf("\nMedia: %.2f", alunos[i].media);      
      } 
 
      printf("\n\n\n"); 
      system("pause"); 
}

Versão modularizada (versão 2), com uso de funções: solicitaNota, calculaMedia, exibeAluno e finalizaPrograma

// Versão 2
#include <stdio.h> 
#include <stdlib.h> 
 
#define MAX_ALUNOS 30 
 
struct TipoAluno { 
      char nome[30]; 
      float media; 
}; 
 
// solicita uma nota exigindo que a mesma esteja na faixa válida: 0 a 10 
float solicitaNota(void) { 
    // a variável nota tem escopo local, ou seja ela só existe dentro desta função 
    float nota; 
    do { 
         scanf("%f", &nota); 
         if(nota < 0 || nota > 10) { 
             printf("Erro, valor deve ser de 0 a 10 \n"); 
         } 
    }while(nota < 0 || nota > 10);   
    return nota; 
} 
 
// calcula a média a partir de duas notas e pontos extras 
// não permitindo que a média ultrapasse de 10 
float calculaMedia(float n1, float n2, float pont) { 
      // a variável media tem escopo local, ou seja ela só existe dentro desta função 
      float media = (n1 + n2)/2 + pont; 
      // não permite que o retorno seja maior que 10 
      if(media > 10) 
            return 10; 
      else 
            return media; 
} 
 
// exibe os dados de uma aluno passado como argumento 
void exibeAluno(struct TipoAluno aluno) { 
      printf("\n\nAluno: %s", aluno.nome); 
      printf("\nMedia: %.2f", aluno.media);      
} 
 
// função sem retorno, contendo comandos para finalizar o programa 
void finalizaPrograma(void) { 
      printf("\n\n\n"); 
      system("pause"); 
} 
 
// programa principal com as chamadas das funções criadas 
int main(void) { 
    // As variáveis criadas aqui dentro (chamadas de variáveis locais) não são 
    // visíveis em outras funções. Variáveis declaradas fora de qualquer função 
    // são chamadas de variáveis globais. 
    // Se houver necessidade de acessar uma variável dentro de outra função   
    // deve-se passa-la como argumento como acontece com: calculaMedia e exibeAluno 
    struct TipoAluno alunos[MAX_ALUNOS]; 
    float nota1, nota2, pontos; 
    int i; 
    for(i=0; i < MAX_ALUNOS; i++) { 
          printf("\nEntre com o nome do aluno: "); 
          gets(alunos[i].nome); 
          fflush(stdin);
          printf("Entre com a primeira nota (0 a 10): "); 
          nota1 = solicitaNota(); 
          printf("Entre com a segunda nota (0 a 10): "); 
          nota2 = solicitaNota(); 
          printf("Entre com os pontos (0 a 10): "); 
          pontos = solicitaNota(); 
          alunos[i].media = calculaMedia(nota1, nota2, pontos); 
    } 
    printf("\n\nExibicao dos dados:"); 
    for(i=0; i < MAX_ALUNOS; i++) 
          exibeAluno(alunos[i]);   
 
    finalizaPrograma(); 
}

Observe a versão 3 do mesmo programa com o acréscimo dos protótipos das funções. Protótipos são apenas a linha de cabeçalho das funções para indicar ao compilador que elas serão definidas mais adiante, normalmente após a funções main.

// Versão 3
#include <stdio.h> 
#include <stdlib.h> 
 
#define MAX_ALUNOS 30 
 
struct TipoAluno { 
      char nome[30]; 
      float media; 
}; 
 
// protótipos das funções 
float solicitaNota(void); 
float calculaMedia(float nota1, float nota2, float pontos); 
void exibeAluno(struct TipoAluno aluno); 
void finalizaPrograma(void); 
 
// programa principal com as chamadas das funções criadas 
int main(void) { 
      // As variáveis criadas aqui dentro (chamadas de variáveis locais) não são 
      // visíveis em outras funções. Variáveis declaradas fora de qualquer função 
      // são chamadas de variáveis globais. 
      // Se houver necessidade de acessar uma variável dentro de outra função   
      // deve-se passa-la como argumento como acontece com: calculaMedia e exibeAluno 
      struct TipoAluno alunos[5]; 
      float nota1, nota2, pontos; 
      int i; 
      for(i=0; i < MAX_ALUNOS; i++) { 
            printf("\nEntre com o nome do aluno: "); 
            fflush(stdin);
            gets(alunos[i].nome); 
            printf("Entre com a primeira nota (0 a 10): "); 
            nota1 = solicitaNota(); 
            printf("Entre com a segunda nota (0 a 10): "); 
            nota2 = solicitaNota(); 
            printf("Entre com os pontos (0 a 10): "); 
            pontos = solicitaNota(); 
            alunos[i].media = calculaMedia(nota1, nota2, pontos); 
      } 
      printf("\n\nExibicao dos dados:"); 
      for(i=0; i < MAX_ALUNOS; i++) 
            exibeAluno(alunos[i]);   
 
      finalizaPrograma(); 
}          
 
// Funções: 
 
// solicita uma nota exigindo que a mesma esteja na faixa válida: 0 a 10 
float solicitaNota(void) { 
      // a variável nota tem escopo local, ou seja ela só existe dentro desta função 
      float nota; 
      do { 
            scanf("%f", &nota); 
            if(nota < 0 || nota > 10) { 
                  printf("Erro, valor deve ser de 0 a 10 \n"); 
            } 
      }while(nota < 0 || nota > 10);   
      return nota; 
} 
 
// calcula a média a partir de duas notas e pontos extras 
// não permitindo que a média ultrapasse de 10 
float calculaMedia(float nota1, float nota2, float pontos) { 
      // a variável media tem escopo local, ou seja ela só existe dentro desta função 
      float media = (nota1 + nota2)/2 + pontos; 
      // não permite que o retorno seja maior que 10 
      if(media > 10) 
            return 10; 
      else 
            return media; 
} 
 
// exibe os dados de uma aluno passado como argumento 
void exibeAluno(struct TipoAluno aluno) { 
      printf("\n\nAluno: %s", aluno.nome); 
      printf("\nMedia: %.2f", aluno.media);      
} 
 
// função sem retorno, contendo comandos para finalizar o programa 
void finalizaPrograma(void) { 
      printf("\n\n\n"); 
      system("pause"); 
}

Exercícios

1. No programa fornecido como exemplo, acrescente na estrutura que representa o aluno um campo para armazenar a quantidade de faltas. Faça as modificações necessárias no programa para que o novo campo seja utilizado na entrada e saída de dados. Dê um bônus de 0,5 pontos na média final para o aluno que não tem faltas.

Crie as seguintes duas funções para resolver o que foi solicitado:

  • a função 'solicitaFaltas' que faz a entrada da quantidade de faltas, tal como acontece como a função 'solicitaNota'
  • a função ‘bonusMedia’, que retorna 0,5 pontos para ser acrescentado na média final (através do acréscimo nos pontos extras) caso o aluno não tenha faltas. Observe que esta função deverá receber como argumento a qtde de faltas.

2. Ainda no exemplo, acrescente a função 'exibeTodosAlunos'. Esta função deverá receber como argumento o vetor contendo todos os alunos e fazer a exibição de cada um através da chamada da função já existente 'exibeAluno'.

Veja uma sugestão de protótipo:

void exibeTodosAlunos(struct TipoAluno turma[]);

Observe que o parâmetro turma indicado com colchetes [] se refere ao vetor inteiro e não somente a um aluno.

3. Modifique o exemplo (juntamente com as alterações propostas nos exercícios 1 e 2) para que a quantidade de alunos possa ser decidida durante a entrada de dados. Por exemplo, permita que o usuário termine a entrada quando o nome for vazio.

Observe que a função exibeTodosAlunos precisará da quantidade de alunos que deixa de ser sempre especificada pela constante MAX_ALUNOS. Veja sugestão de protótipo:

void exibeTodosAlunos(struct TipoAluno turma[], int qtde);

4. Crie um programa que apresente um menu de seleções no programa principal (função main) permitindo o usuário escolher uma das quatro operações aritméticas. Em seguida, solicite os dois operandos, calcule e exiba o resultado da operação escolhida para dois valores informados.

Exemplo de tela na console:

----------------------------------- 
Escolha uma opcao: 
1 – somar 
2 – subtrair 
3 – multiplicar 
4 – dividir 
-----------------------------------

Faça as seguintes funções:

  • uma função para exibir o menu, permitir que o usuário escolha e devolver o número da opção escolhida,
  • quatro funções para representar as quatro operações aritméticas. Cada uma deverá receber os dois números (operandos) e devolver o resultado da operação.

No programa principal, exiba o resultado.
Obs.: use o comando switch, no programa principal, para classificar a opção escolhida.

5. Faça um programa para receber um número inteiro do usuário. Em seguida verifique se ele é:
- par
- divisível por três
- divisível por cinco.
- primo
- perfeito (é aquele cuja soma de seus divisores (excluindo ele próprio) é igual a ele mesmo, por exemplo, o número 6 tem como divisores 1,2 e 3, cuja soma é 6).

Crie uma função para cada item acima. Cada função deve receber o número a ser verificado, como argumento, e devolver ‘1’ para verdadeiro e ‘0’ para falso.

6. Desenvolva um programa para permitir o cadastro de 50 alunos. Cada aluno deve ser representado por uma estrutura formada por uma matrícula (exatamente 5 caracteres contendo letras e números), um nome (máximo de 40 caracteres) e um histórico de notas. O histórico de notas, que também deve ser representado por uma estrutura, é composto de duas notas de provas, uma nota de trabalho e uma nota de pontuação extra.

Elabore uma função para calcular e retornar a média das notas. O cálculo deverá ser realizado somando-se as quatro notas e dividindo-se por três. Se o resultado for superior a 10 deve-se retornar 10.

Exiba todas as informações cadastradas e a média das notas de cada aluno.

Calcule e exiba a quantidade de alunos cuja média foi de 7 a 10.

Exiba a maior média dos 50 alunos.

Obs.:

  • não permita digitação de notas fora da faixa de 0 a 10;
  • sempre que possível reaproveite o código através da modularização;
  • escreva o protótipo da função que calcula a média;
  • use somente variáveis locais para resolver este problema.

7. Desenvolva um programa para calcular o valor de funções trigonométricas. Ofereça para o usuário um menu com as opções:

----------------------------------- 
Escolha a função trigonométrica: 
1 – seno 
2 – cosseno 
3 – tangente 
-----------------------------------

Use as Séries de Taylor para realizar os cálculos do seno e cosseno. Solicite ao usuário o valor do ângulo em graus. Observe que as Séries de Taylor trabalham com os ângulos em radianos. A quantidade de interações deve ser determminada por uma constante (#define)
Informações sobre série de Taylor: http://pt.wikipedia.org/wiki/S%C3%A9rie_de_Taylor

  • $sen(x) = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \cdots, \forall x \in \mathbb{R}$
  • $cos(x) = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} - \cdots, \forall x \in \mathbb{R}$
  • $tg(x) = \frac{sen(x)}{cos(x)}$

Faça uma função para exibir o menu, e mais 3 funções, uma para cada operação. Cada uma destas 3 funções deverá receber o ângulo (em radianos) e retornar o resultado da função trigonométrica.

Faça também uma função para converter um ângulo de graus para radianos.

A função para calcular a tangente deve usar as funções seno e cosseno já construídas.

8. Desenvolva um programa para permitir o cadastro de 500 veículos. Cada veículo deve ser representado por uma estrutura formada por um marca (máximo de 30 caracteres), um modelo (máximo de 40 caracteres), o ano de fabricação e um conjunto de dados técnicos. O conjunto de dados técnicos, que também deve ser representado por uma estrutura, é composto de: potência em CV, cilindradas e número de válvulas.

Elabore uma função para calcular a performance estrutural do veículo através da seguinte fórmula: dobro da potência somado com o valor das cilindradas, e dividido pela quantidade de válvulas. Se a quantidade de válvulas for maior ou igual a 16, multiplique a potência por 3 ao invés de 2.

Exiba todas as informações cadastradas, incluindo a performance estrutural.

Calcule e exiba a quantidade de veículos cuja performance estrutural é inferior a 150.

Exiba a maior performance estrutural entre os 500 veículos digitados.

Obs.:

  • sempre que possível reaproveite o código através da modularização;
  • escreva o protótipo da função que calcula a performance estrutural;
  • use somente variáveis locais para resolver este problema.

9. A Biblioteca Padrão da Linguagem C possui várias funções para trabalhar com strings (vetores de caracteres).

Entre elas existem três que são muito úteis:

  • strlen – recebe uma string e retorna o seu tamanho, ou seja, a quantidade de caracteres.
  • strcpy – recebe duas strings e copia a segunda para a primeira, ou seja, cada caractere da segunda é copiado para a respectiva posição na primeira.
  • strcmp – recebe duas strings e devolve a resultado da comparação das duas. Retorna 0 se forem iguais, 1 se a primeira for alfabeticamente maior que a segunda e, -1 se a segunda for alfabeticamente maior que a primeira.

Reconstrua as três funções acima, criando o seu algoritmo.

Faça um programa que receba duas strings para testar as três funções.

10. Faça um programa para receber 20 itens de uma agenda de compromissos compostos de: nome do compromisso, data no formato dd-mmm-aa e horário no formato hh:mm pm/am.

Exemplos de 2 itens de compromisso da agenda:
Reunião diretoria, 20-jun-10, 10:40 AM
Apresentação proposta, 02-dez-10, 04:30 PM

Crie adequadamente estruturas para fazer o armazenamento dos dados.

Faça um programa com um menu que ofereça as seguintes opções:

MENU
1 – Listar todos os compromissos. 
2 – Listar todos os compromissos apresentando os horários no formato de hora 24h. 
3 - Exibir os compromissos de uma determinada data fornecida pelo usuário. 
4 - Exibir a quantidade de compromissos de um determinado mês fornecido pelo usuário.

Crie funções para:
- exibir o menu de opções;
- executar cada opção do menu;
- converter a hora do formato AM/PM para 24h
- exibir a data no formato aa-mmm-aa
- exibir a hora no formato hh:mm AM/PM

Obs.: para as opções 3 e 4 do menu use a função strcmp criada na questão anterior (se ainda não tiver criado, use a que é fornecida pela Biblioteca Padrão).
A função strcmp serve para comparar strings, como por exemplo, para verificar se o mês digitado no vetor de caracteres mes é dezembro, usa-se:

if(strcmp(mes, ”dez) == 0)