UFES CEUNES Ciência da Computação e Engenharia de Computação Programação Estruturada 2º período 2013/1 Lista de exercícios 07 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. Essas partes, trechos, ou módulos, na Linguagem C, são chamadas de funções e, espera-se que elas possuam um objetivo específico dentro do programa, realizando, de fato, uma funcionalidade. Benefícios da modularização: Permite testar e achar erros mais facilmente: pode-se testar 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 utilizar trechos de programa úteis em outras situações, no próprio programa ou em outro programa. Aumenta o nível de alterabilidade do programa: basta alterar uma vez o módulo, pois ele já é reusado em outros lugares. Aumenta a legibilidade do programa: principalmente para o programa principal que fica menor, mais limpo e, consequentemente, fica mais fácil de ser lido. Permite a construção de abstrações sobre os problemas: foca-se na resolução de um problema com o uso de funções já construídas anteriormente e não nos detalhes de uma programação específica que foi encapsulada dentro da função. A Linguagem C possui uma grande biblioteca de funções já prontas. Algumas delas já usamos nas aulas: printf, scanf, srand, rand, gets, pow, sqrt, fflush etc. Como motivação inicial para perceber a importância da modularização, estude os dois exemplos a seguir. Exemplo 1: No código fornecido a seguir existem muitas repetições além do tamanho excessivo da função main. Este código soluciona o seguinte problema: Deseja-se armazenar, de uma turma composta de 30 alunos, apenas 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, adicionando-se, em seguida, os pontos de participação, mas sempre obedecendo ao limite máximo de 10 para a média. Para cada uma das notas e também para os pontos não permita que seja digitado valor fora da faixa de 0 a 10. Após a entrada de dados deve-se exibir a relação de alunos com os seus nomes e médias. Lista de exercícios 07 Programação Estruturada 2013/1 página 1 / 10
// Versão 1: SEM MODULARIZAÇÃO #include <stdio.h> #include <stdlib.h> #define MAX_ALUNOS 30 #define TAM_NOME 50 struct TipoAluno { char nome[tam_nome]; 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", ¬a1); 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", ¬a2); 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); return 0; Lista de exercícios 07 Programação Estruturada 2013/1 página 2 / 10
// Versão 2: MODULARIZADO #include <stdio.h> #include <stdlib.h> #define MAX_ALUNOS 30 #define TAM_NOME 50 struct TipoAluno { char nome[tam_nome]; float media; ; // protótipos das funções float solicitanota(void); float calculamedia(float nota1, float nota2, float pontos); void exibealuno(struct TipoAluno aluno); // 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: "); 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]); return 0; Lista de exercícios 07 Programação Estruturada 2013/1 página 3 / 10
// 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", ¬a); 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); Exemplo 2: O programa a seguir calcula o cosseno dos ângulos pares de 0 a 180, sem usar math.h. O ângulo em graus é convertido para radianos e em seguida, usando a série de Taylor, proposta como exercício 33 da lista 3, calcula-se o cosseno deste ângulo. Um laço de 0 a 180 de 2 em 2 faz a iteração principal para processar os cálculos. Série de Taylor para o cosseno: Lista de exercícios 07 Programação Estruturada 2013/1 página 4 / 10
// versão 1: SEM MODULARIZAÇÃO #include <stdio.h> #define PI 3.14159265358979323846 #define QTDE_TERMOS 7 int main() { int angulograus, i, sinal, fatorial; float anguloradianos, numerador, resultado; for(angulograus=0; angulograus<=180; angulograus+=2) { // conversão de graus para radianos anguloradianos = angulograus*pi/180; // inicializa as variáveis sinal=1; fatorial=2; numerador=1; resultado=1; // calcula o cosseno de angulograus for (i = 1; i < QTDE_TERMOS; i++) { sinal = -1*sinal; numerador = numerador*anguloradianos*anguloradianos; resultado = resultado + sinal*numerador/fatorial; fatorial = fatorial*(i*2+1)*(i*2+2); printf("cosseno de %d graus (%.2f radianos)=%.2f\n",angulograus,anguloradianos,resultado); return 0; Na versão 2, observe que foram criadas duas funções: uma para transformar graus em radianos, e outra para calcular o cosseno. Desta forma o programa principal ficou bem mais limpo e com melhor legibilidade. // versão 2: MODULARIZADO #include <stdio.h> #define PI 3.14159265358979323846 #define QTDE_TERMOS 7 // protótipos das funções (é o cabeçalho das funções que serão usadas) float convertegrausemradianos(float graus); float calculacosseno(float graus); int main() { int angulograus; float cosseno; for(angulograus=0; angulograus<=180; angulograus+=2) printf("cosseno de %d graus (%.2f radianos) = %.2f\n", angulograus, convertegrausemradianos(angulograus),calculacosseno(angulograus)); return 0; float convertegrausemradianos(float graus) { return graus*pi/180; Lista de exercícios 07 Programação Estruturada 2013/1 página 5 / 10
float calculacosseno(float graus) { int i, sinal=1, fatorial=2; float numerador=1, resultado=1, anguloradianos; anguloradianos = convertegrausemradianos(graus); for (i = 1; i < QTDE_TERMOS; i++) { sinal = -1*sinal; numerador = numerador*anguloradianos*anguloradianos; resultado = resultado + sinal*numerador/fatorial; fatorial = fatorial*(i*2+1)*(i*2+2); return resultado; Exercícios 1. No programa do exemplo 1, 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. Para isso, crie as seguintes duas funções: a função 'solicitafaltas' que faz a entrada da quantidade de faltas. Observe o funcionamento semelhante da função 'solicitanota' a função bonusmedia, que retorna 0,5 pontos sempre que o aluno não tiver faltas. Para isso, ela deverá receber a quantidade de faltas como argumento. Faça a sua chamada de dentro da função calculamedia para acrescentar a pontuação de bônus de forma apropriada e altere o que for necessário em calculamedia. Sugestão para o protótipo destas funções: float solicitanota(void); float calculamedia(float nota1, float nota2, float pontos, int fal); float bonusmedia(int fal); 2. Ainda no exemplo 1, 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'. 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. Após a sua construção, use-a no programa principal. Lista de exercícios 07 Programação Estruturada 2013/1 página 6 / 10
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 finalize 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. 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 sobre os dois valores informados. Exemplo de tela na console: ----------------------------------- Escolha uma opcao: 1 somar 2 subtrair 3 multiplicar 4 dividir ----------------------------------- Modularize: Crie uma função para exibir o menu, permitir que o usuário escolha uma das 4 opções e devolver o número da opção escolhida. Em caso de opção errada, apenas retorne o número errado. Crie quatro funções para representar as quatro operações aritméticas. Cada uma delas deverá receber os dois números (operandos) como argumentos e devolver o resultado da operação. Na função que trata a divisão, verifique os casos de divisão por zero e divisão indeterminada (zero por zero), nesses dois casos, exiba mensagem de erro e retorne zero. No programa principal, chame a função que exibe o menu e solicita a opção, em seguida solicite ao valores dos operandos, depois, através de um switch chame a função específica da operação selecionada e, finalmente, exiba o resultado. 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, de tal forma que receba o número a ser verificado, como argumento, e devolva 1 para verdadeiro e 0 para falso. Lista de exercícios 07 Programação Estruturada 2013/1 página 7 / 10
6. Complete o programa fornecido, definindo as funções ordena e exibe, de tal forma que se tenha a saída mostrada. #include <stdio.h> #include <string.h> #define MAX 10 struct TipoDado { char nome[max]; int idade; ; // protótipos das funções void ordena(struct TipoDado dados[], char chave, int qtde); void exibe(struct TipoDado dados[], int qtde); int main() { struct TipoDado dados[] ={{"mateus",20,{"maria",25,{"marina",18,{"marcos",40; int qtde = sizeof(dados)/sizeof(dados[0]); // no gcc win: 64/16 = 4 printf("dados sem ordenacao:\n"); exibe(dados,qtde); ordena(dados,'n',qtde); // ordena pelo nome printf("\ndados ordenados pelo nome:\n"); exibe(dados, qtde); ordena(dados,'i',qtde); // ordena pela idade printf("\ndados ordenados pela idade:\n"); exibe(dados,qtde); return 0; Saída: Dados sem ordenacao: Nome: mateus Idade: 20 Nome: maria Idade: 25 Nome: marina Idade: 18 Nome: marcos Idade: 40 Dados ordenados pelo nome: Nome: marcos Idade: 40 Nome: maria Idade: 25 Nome: marina Idade: 18 Nome: mateus Idade: 20 Dados ordenados pela idade: Nome: marina Idade: 18 Nome: mateus Idade: 20 Nome: maria Idade: 25 Nome: marcos Idade: 40 7. 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. Lista de exercícios 07 Programação Estruturada 2013/1 página 8 / 10
Elabore uma função para calcular e retornar a média das notas. Esta média é calculada 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. Além disto, calcule e exiba a quantidade de alunos cuja média foi de 7 a 10, e 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. 8. Sem usar math.h 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 determinada por uma constante (#define) 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. 9. 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. Lista de exercícios 07 Programação Estruturada 2013/1 página 9 / 10
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. 10. 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, recriando o seu algoritmo. Faça um programa que receba duas strings para testar as três funções. 11. 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) Lista de exercícios 07 Programação Estruturada 2013/1 página 10 / 10