Introdução à Computação - intranet.ifs.ifsuldeminas.edu.brkleber.rezende/anterior... · de...
Transcript of Introdução à Computação - intranet.ifs.ifsuldeminas.edu.brkleber.rezende/anterior... · de...
Sub Rotinas
Estrutura de Dados
Prof. Kleber Rezende
Considerações Iniciais
Uma dos métodos mais comuns e
amplamente utilizados em programação
de computadores é o Top-Down.
Nesta abordagem um problema é
dividido em problemas menores.
Após sua divisão em um número
adequado de partes, chamadas de
subproblemas ou sub-rotinas.
Considerações Iniciais
Estes subproblemas são resolvidos
individualmente, levando a solução do
problema completo.
O processo é bastante simples.
Inicialmente deve-se definir o que deve
ser feito, sem levar em consideração
como será feito.
Considerações Iniciais
Se os subproblemas gerados com a
pergunta “o que” forem suficientemente
simples, deve-se então pensar em como
resolver cada um deles, considerando os
aspectos de algoritmos ou uma
linguagem de programação específica.
Exemplo
Crie um algoritmo que leia o nome o
número de filhos e o salário bruto de
uma pessoa. Em seguida o programa
deve calcular e imprimir o nome e o
salário final do funcionário. O salário
final é calculado descontando o imposto
de renda do salário bruto e adicionando
um auxílio de acordo com o número de
filhos desta pessoa (auxílio família).
Exemplo
As taxas de desconto do imposto de renda e o
valor do auxílio família são dados abaixo.
Imposto de Renda:
Salário até R$ 1000,00 – Isento.
De R$ 1000,01 a R$ 1800,00 – 15%.
Acima de 1800,00 – 27,5%.
Auxílio Família:
1 filho – R$ 100,00
2 filhos – R$ 180,00
3 ou mais filhos – R$ 240,00
Possível Solução
1. Cálculo do Salário
1.1 Ler os dados de entrada
1.2 Calcular o desconto do imposto de renda
1.2.1 Verificar faixa salarial
1.2.2 Fazer o desconto
1.3 Calcular o Auxílio Família
1.3.1 Verificar o número de filhos
1.3.2 Calcular o abono
1.4 Calcular o Salário Líquido
1.5 Imprimir os resultados
Possível Solução
Considerações Iniciais
A partir deste momento o programador
deve se preocupar com cada um dos
problemas individualmente, tornando
assim o processo de resolução mais
simples.
Considerações Iniciais
É importante observar que neste caso a
divisão do problema principal apenas
uma vez não foi suficiente, já que os
dois subproblemas gerados (Desconto
de Imposto de Renda e Cálculo do
Auxílio Família) ainda não eram tão
simples de serem resolvidos.
Considerações Iniciais
Desta forma, o processo de divisão foi
repetido até que o programador
considerasse que todos os subproblemas
gerados fossem suficientemente simples.
Considerando que cada pessoa possui
características próprias para resolver
problemas, vale destacar que não existe
uma única quantidade de divisões que
pode ser considerada correta.
Considerações Iniciais
É importante que cada pessoa
desenvolva este processo de forma a
facilitar ao máximo o processo de
codificação, sem se preocupar se o
número de subproblemas gerados por
ele é igual ao apresentado por outras
pessoas.
Codificando ...
main ()
{
char nome[15];
int nfilhos;
float IR=0, auxilio, sliquido, sb, desconto;
//LER OS DADOS DE ENTRADA
printf("digite o nome da pessoa: ");
scanf("%s", nome);
printf("Entre com o numero de filhos: ");
scanf ("%d", &nfilhos);
printf("Entre com o salario bruto: ");
scanf ("%f", &sb);
//continua ...
Codificando ...
//...continuação
//CÁLCULO DO IMPOSTO DE RENDA
//VERIFICAR A FAIXA SALARIAL
if ((1000 < sb) && (sb <= 1800))
IR = sb * 0.15;
else if (sb > 1800)
IR = sb * 0.275;
//continua ...
Codificando ...
//...continuação
//CÁLCULO DO AUXÍLIO
//VERIFICACAO DO NUMERO DE FILHOS
switch (nfilhos)
{
case 0: auxilio = 0; break;
case 1: auxilio = 100; break;
case 2: auxilio = 180; break;
default: auxilio = 240; break;
}
//continua ...
Codificando ...
//...continuação
//CÁLCULO DO SALÁRIO LÍQUIDO
sliquido = sb - IR + auxilio;
//IMPRESSÃO DOS RESULTADOS
printf ("%s, ", nome);
printf ("o salario liquido eh: %.2f", sliquido);
} //FIM DA ROTINA MAIN
Modularização
É a divisão de um programa em partes gerenciáveis
(módulos) e, em seguida, na montagem destas
partes em um fluxo coerente e lógico.
A modularização em conjunto com a abordagem
Top-Down, são de extrema importância à medida
que o tamanho dos programas desenvolvidos
aumenta.
Nestes casos, a resolução de todo o problema em
um único bloco de código é praticamente inviável
pois torna o programa “ilegível” o que dificulta a
manutenção e atualização do mesmo.
Modularização
Além disto a modularização possibilita que:
1. Partes dos programas sejam construídas e
testadas separadamente;
2. Trechos de códigos que aparecem várias vezes
dentro do programa sejam implementados e
testados uma única vez;
3. Bibliotecas sejam construídas com módulos que
podem ser utilizados em diferentes programas.
Modularização
As ferramentas utilizadas para modularizar um
programa são as sub-rotinas.
Quando um programa é desenvolvido
utilizando a modularização, o mesmo é
composto por um, e apenas um, programa
principal, e por uma série de módulos (sub-
rotinas).
Esta técnica é conhecida como Programação
Estruturada.
Modularização
Programa Principal é o bloco de código por
onde um programa inicia sua execução. Este
pode conter os comandos de controle de um
programa (sequência, seleção e repetição),
bem como a chamada para as suas sub-
rotinas. Apesar de ser mais fácil desenvolver
primeiro o programa principal e em seguida os
módulos necessários, em linguagens como
ANSI C ele deve ser o último bloco do
programa.
Modularização
Sub-rotinas são blocos de código utilizados
para resolver pequenas partes do problema.
Eles podem conter os mesmos elementos do
programa principal, inclusive declaração de
tipo e variáveis próprias, chamadas para
outras sub-rotinas, etc.
Sua diferença, está no fato de que as sub-
rotinas não são executadas automaticamente
quando o programa é iniciado, e sim, apenas
quando são chamadas.
Modularização
Portanto, o simples fato de declarar uma sub-
rotina não implica na execução da mesma.
Para que a execução seja efetuada a sub-
rotina deve ser chamada pelo programa
principal ou por outro módulo.
Modularização
Uma sub-rotina deve sempre retornar um
valor ao módulo que a chamou em seu próprio
nome.
Este valor é lido ou calculado dentro da sub-
rotina (função) e utilizado no programa
principal no cálculo de alguma expressão ou
simplesmente atribuindo-o a uma outra
variável.
Modularização
Na declaração de uma sub-rotina deve-se
sempre definir o tipo do valor que ela retorna
em seu nome.
Esta definição deve ser feita antes de seu
nome.
Caso a sub-rotina não retorne valor, deve-se
usar a palavra reservada void como tipo de
retorno.
Modularização
Na declaração de uma sub-rotina deve-se
sempre definir o tipo do valor que ela retorna
em seu nome.
Esta definição deve ser feita antes de seu
nome.
Caso a sub-rotina não retorne valor, deve-se
usar a palavra reservada void como tipo de
retorno.
Voltando ao exemplo anterior
Resolva o problema anterior (cálculo do
salário líquido) utilizando as estruturas de
modularização (sub-rotinas)
Codificando ...
char nome[15];
int nfilhos;
float IR=0, auxilio, sliquido, sb, desconto;
void LerDados ()
{
//LER OS DADOS DE ENTRADA
printf("digite o nome da pessoa: ");
scanf("%s", nome);
printf("Entre com o numero de filhos: ");
scanf ("%d", &nfilhos);
printf("Entre com o salario bruto: ");
scanf ("%f", &sb);
}
Codificando ...
float CalculaImposto ()
{
//CÁLCULO DO IMPOSTO DE RENDA
//VERIFICAR A FAIXA SALARIAL
if ((1000 < sb) && (sb <= 1800))
return sb * 0.15;
else if (sb > 1800)
return sb * 0.275;
else
return 0;
}
Codificando ...
float CalculaAuxilio ()
{
//CÁLCULO DO AUXÍLIO
//VERIFICAÇÃO DO NÚMERO DE FILHOS
switch (nfilhos)
{
case 0: return 0; break;
case 1: return 100; break;
case 2: return 180; break;
default: return 240; break;
}
}
Codificando ...
float CalculaLiquido ()
{
//CÁLCULO DO SALÁRIO LÍQUIDO
return sb - IR + auxilio;
}
void ImprimeResultados ()
{
//IMPRESSÃO DOS RESULTADOS
printf ("%s, ", nome);
printf ("o salario liquido eh: %.2f", sliquido);
}
Codificando ...
main ()
{
LerDados ();
IR = CalculaImposto ();
auxilio = CalculaAuxilio ();
sliquido = CalculaLiquido ();
ImprimeResultados ();
} //FIM DA ROTINA MAIN
Escopo de Variáveis
Define-se como Escopo de uma variável a
abrangência que a mesma tem dentro de um
programa.
Com relação a este aspecto as variáveis
podem ser Globais ou Locais.
Se uma variável é declarada fora de qualquer
sub rotina, esta é chamada de variável global
e pode ser referenciada (utilizada) em
qualquer parte do programa (programa
principal, procedimentos e funções).
Escopo de Variáveis
Quando uma variável é declarada dentro de
uma função, esta é conhecida como uma
variável local e só pode ser referenciada
dentro da função em que foi declarada, ou em
funções que tenham sido criadas dentro do
módulo onde a variável foi declarada.
Isto permite que uma grande quantidade de
memória seja economizada em programas
com muitas variáveis.
Escopo de Variáveis
Variável global é uma das ferramentas
utilizadas para comunicação (passagem de
valores) entre diferentes módulos do
programa.
Exemplo
int base, expoente, resultado;
void LerDados ()
{
//LER OS DADOS DE ENTRADA
printf("digite a base: ");
scanf("%d", &base);
printf("digite o expoente: ");
scanf ("%d", &expoente);
}
Fazer um programa que leia dois números
(BASE e EXPOENTE) e retorne como resultado
o valor de BASE elevado ao EXPOENTE..
Exemplo
void Calcule_Potencia()
{
int i;
resultado = 1;
for (i=1; i <= expoente; i++)
resultado = resultado * base;
}
void Escreva_Dados ()
{
//IMPRESSÃO DOS RESULTADOS
printf ("O número %d elevado a potencia %d é
igual a %d.", base, expoente, resultado);
}
Exemplo
main ()
{
LerDados ();
Calcule_Potencia ();
Escreva_Dados ();
} //FIM DA ROTINA MAIN
Escopo de Variáveis
Apesar de possível, não é aconselhado utilizar
variáveis globais para passar valores entre
diferentes módulos do programa.
Isto, além de em muitos casos alocar memória
desnecessariamente, faz com que a
modularidade do programa não seja tão
eficiente, gerando erros e dificultando a
depuração e manutenção dos programas.
Escopo de Variáveis
Alguns exemplos de problemas decorrentes
da utilização de variáveis globais dentro de
funções são:
pode-se perder o controle de quais módulos estão
acessando uma determinada variável;
é mais difícil aproveitar uma função já prontos em
outros programas.
Tipos de Parâmetros
Para enviar dados de um módulo para outro
devem ser utilizados Parâmetros.
É através deles que os dados necessários
para a resolução de um problema dentro de
uma função são passados para as mesmas,
bem como valores são retornados destes
módulos para o programa principal.
Tipos de Parâmetros
Mesmo não sendo obrigatório, aconselha-se
que toda variável global seja utilizada apenas
no programa principal.
Quando esta precisar ser referenciada dentro
de uma função, ela deve ser passada como
parâmetro, a fim de evitar erros na lógica do
programa.
Tipos de Parâmetros
Existem dois tipos de parâmetros: os
parâmetros formais e os atuais.
Parâmetros formais são aqueles declarados
em uma função específica, que recebem os
valores vindos do módulo (programa principal
ou outro módulo) que o chamou.
Tipos de Parâmetros
Os parâmetros formais ficam armazenados na
memória apenas enquanto a sub rotina na
qual foram declarados está sendo executada.
Após isto, estas variáveis deixam de existir e o
seu valor é apagado, assim como as variáveis
locais daquele módulo.
Tipos de Parâmetros
Os parâmetros atuais são as variáveis cujos
valores são passados para os parâmetros
formais no início da execução de uma sub
rotina e que, em alguns casos, recebem de
volta os valores dos parâmetros formais ao
término da execução da mesma.
O fato de um parâmetro atual receber de volta
o valor do parâmetro formal ao final da
execução de um módulo depende da forma
com que o este foi declarado.
Formas de declaração de
Parâmetros Formais
Os parâmetros formais podem ser declarados
de duas maneiras.
A primeira forma de passagem de parâmetros
é a passagem por valor.
Nela é feita uma cópia do valor da variável
(parâmetro atual) que é armazenado no
parâmetro formal dentro da sub rotina
chamada.
Formas de declaração de
Parâmetros Formais Desta forma, qualquer alteração feita no
parâmetro formal dentro da sub rotina, não
terá efeito na variável original (parâmetro
atual).
Este tipo de passagem é utilizado quando se
deseja enviar algum valor para as funções,
sendo desnecessário o seu retorno para o
bloco chamador (parâmetros de entrada).
Neste caso qualquer alteração nos
parâmetros formais não afetaria os
parâmetros atuais.
Formas de declaração de
Parâmetros Formais
A segunda forma é a passagem por
referência.
Nela, o endereço da variável (parâmetro atual)
é enviada do bloco chamador (este pode ser o
programa principal ou qualquer função do
programa), para o bloco chamado.
Formas de declaração de
Parâmetros Formais
Neste caso, o parâmetro formal não é uma
variável comum que armazena um valor.
Ele armazena uma referência para o
parâmetro atual.
Assim, qualquer alteração feita no parâmetro
formal dentro da sub rotina chamada afetará a
variável (parâmetro atual) no bloco chamador.
Formas de declaração de
Parâmetros Formais
Este tipo de passagem de parâmetros é
comum quando se deseja que o módulo
chamado, retorne alguma informação através
daquele parâmetro (parâmetro de saída).
Na linguagem C, para declarar que um
parâmetro é passado por referência deve ser
adicionado o caractere * antes do nome do
parâmetro formal.
Formas de declaração de
Parâmetros Formais
Na linguagem C, para chamar uma função
necessite que um parâmetro seja passado por
referência deve ser adicionado o caractere &
antes do nome do parâmetro atual.
Exemplo:
void funcao_exemplo (int *parFormal)
{ }
void main ()
{ int parAtual;
funcao_exemplo (&parAtual); }
Exercícios
1) Crie um programa que calcule o fatorial de dois
números e imprima a soma destes números. Utilize
funções para a modularização da solução.
2) Crie uma função que retorne o MENOR entre dois
valores inteiros.
3) Elaborar um programa que utilize uma sub rotina
para calcular a serie de Fibonacci de N termos. A
série de Fibonacci é formada pela sequência : 1, 2, 3,
5, 8, 13, 21, 34, ..., etc. Esta série caracteriza-se pela
soma de um termo posterior com o seu subsequente,
e ela deve ser impressa até que o último elemento
não ultrapasse o valor de entrada N.
Exercícios
4) Um programa que leia o nome o número de filhos e o
salário bruto de uma pessoa. Em seguida o programa
deve calcular e imprimir o nome e o salário final do
funcionário. O salário final é calculado descontando o
imposto de renda do salário bruto e adicionando um
auxílio de acordo com o número de filhos desta
pessoa (auxílio família). Faça a passagem de
parâmetros por valor e por referência ao invés de
utilizar variáveis globais.
As taxas de desconto do imposto de renda e o valor
do auxílio família são as mesmas informadas
anteriormente.
Exercícios
5) Faça um algoritmo que sorteie um número entre 1 e
50*. O usuário terá direito a três palpites, e a cada
tentativa o programa deve dizer se o número
sorteado é maior ou menor que o número digitado
pelo usuário. A execução do programa deve terminar
quando o usuário acertar o número ou tiver feito as
três tentativas sem sucesso. No final, o programa
deve emitir uma mensagem parabenizando o
usuário, caso tenha acertado, ou dizendo que ele não
obteve sucesso.
Exercícios
* O comando 1 + rand() % 50; sorteia um número entre 1
e 50. E o comando srand( (unsigned)time(NULL) );
renova o sorteio e evita que seja sempre sorteado o
mesmo número.
6) Continuando com o exercício anterior, aprimore o
programa para caso o usuário não tenha acertado.
Faça com que o programa dê mais uma chance para
o usuário, sendo que essa chance será calculada
pelo próprio programa através da média (inteira) dos
três palpites do usuário. No final, o programa deve
emitir uma mensagem parabenizando o usuário, caso
tenha acertado, ou dizendo que ele não obteve
sucesso.
Exercícios
7) Elaborar um programa que utilize uma sub-rotina
(função) que recebe um número e retorna esse
número sempre positivo.
8) Faça uma função que recebe por parâmetro o raio de
uma esfera e calcula o seu volume (v = 4/3.P.R3)
9) Faça uma função que receba a idade de uma pessoa
em anos, meses e dias e retorne essa idade
expressa em dias (Considere que os anos possuam
365 dias, e que os meses possuam 30 dias).