SUBPROGRAMAS
A identificação de problemas mais complexos resultará no desenvolvimento de algoritmos também mais complexos para resolvê-los.
Uma abordagem eficiente para este tipo de problema é a divisão do problema mais complexo em problemas mais simples de serem resolvidos.
Este método é conhecido como modularização, onde um grande problema é divido em problemas menores e a solução destes problemas menores resultará na solução do problema maior (mais complexo). Estes programas menores são denominados sub-rotinas, módulos, subprogramas ou sub-algoritmos.
Um subprograma é um trecho de um algoritmo (futuro programa) maior (mais complexo) que realiza qualquer operação computacional estudada até agora (entrada, processamento, saída). Ele efetua parte de uma tarefa que um algoritmo maior deverá executar. O algoritmo que aciona um subprograma é chamado de algoritmo principal daquele subprograma.
Observe a seguir a representação da lógica funcional de uma algoritmo elaborado com alguns subprogramas ou módulos.
O funcionamento de um subprograma corresponde a implementação de uma função, no sentido matemático da expressão, pois um subprograma também retorna um único valor, de um ou mais valores manipulados em uma ou mais operações realizadas por esta função.
A expressão "função" também é usada na elaboração de um subprograma, onde ela identifica a disponibilização de um ou mais subprogramas para um algoritmo principal, sendo a expressão funcao uma palavra reservada.
É um subprograma iniciado pela palavra reservada funcao, seguida do tipo de dado referente ao seu resultado, um identificador que fornece um nome à função além de uma lista de parâmetros.
A lista de parâmetros consiste nos valores que o algoritmo principal possui e o subprograma precisa usar para obter, ou gerar, outro dado importante na solução almejada pelo algoritmo.
O acionamento de qualquer subprograma ocorre por meio da especificação do seu nome, seguido da lista de parâmetros a serem manipulados pelo subprograma (função).
Esta lista tem a sua representação opcional ao programador, pois pode não existir nenhum valor do algoritmo que seja necessário ao subprograma.
Uma função possui somente dois momentos importantes no algoritmo:
Primeiro momento é da declaração e especificação das tarefas/operações (seu corpo) que a função deverá executar;
Segundo momento é a utilização ou acionamento da função que pode acontecer várias vezes depois da sua criação e dentro do algoritmo no qual ela também faz parte.
Sintaxe:
// Obejtivo: // Parâmetro: // Retorno: funcao <tipo de dado> <identificador> (<lista de parâmetros>) <tipo de dado> <identificador>; instrução 1 instrução 2 : instrução n retorna(<valor>) fimFuncao
onde:
funcao é a palavra reservada que identifica um tipo de subprograma
<tipo de dado> é um tipo de dado válido (inteiro, real, caracter, lógico)
<identificador> é o nome atribuído a função, aos parâmetros e variáveis
<lista de parâmetros> são os parâmetros usados no subprograma
<valor> representa o único valor que a função retorna para seu acionador (ou chamador)
Os parâmetros de uma função são dados fundamentais que a função deve ter acesso para alcançar seu objetivo. Por exemplo, se você tem uma função denominada media que calcula a média aritmética de dois números, é essencial que essa função "saiba" quais são os números que serão usados para o cálculo da média, do contrário, ela não pode efetuar os cálculos. Pois bem, esses dois números serão disponibilizados à função por meio de parâmetros.
Portanto, a estrutura descritiva dessa função media seria:
// Objetivo: Calcular a média de dois números // Parâmetro: numeros que terão sua média calculada // Retorno: valor da média dos dois números funcao real media(real num_1, real num_2) real resultado; resultado = ((num_1 + num_2) / 2); retorna (resultado); fimFuncao
onde num_1 e num_2 são parâmetros da função media descrita anteriormente.
A sintaxe de criação da função exige o cabeçalho da mesma, coerente com as suas características, onde o nome, seus parâmetros e o retorno sejam corretamente pensados e elaborados de forma a resolver o problema a que ela se propõe.
Na identificação ou descrição das tarefas/operações realizadas pela função (definição do seu corpo) são descritas as declarações de variáveis internas da função (variáveis locais), as constantes e outros subprogramas que possam também ser declarados dentro da função. A partir da palavra reservada funcao inicias-se a elaboração do subprograma (função) até a expressão fimFuncao, onde o cabeçalho da função é elaborado e seu corpo também é descrito (desenvolvido).
Na utilização, também denominada acionamento ou chamada da função, o algoritmo que declarou a função pode acioná-la por meio do seu nome e seus parâmetros, efetuando a chamada ou acionamento da função. Este acionamento tem a similaridade com a chamada de uma colega que está distante. Para que ela te ouça você deve chamá-la pelo seu nome e ela estará "acionada" (com atenção) para ver o que você deseja lhe falar (passar seus parâmetros para ela saber o que fazer para te atender).
Exemplo:
O algoritmo abaixo calcula a média aritmética de cada aluno em uma turma de 50 estudantes. O interessante é que o cálculo de cada média é feito por uma única função, que recebe como parâmetros dois números e retorna a média de cada um dos integrantes desta turma, ou seja, a mesma função é acionada 50 vezes e resolve o problema corretamente.
algoritmo mediaPorAluno; // Síntese // Objetivo: calcular a média para cada aluno da turma // Entrada : duas notas para cada aluno // Saída : média de cada aluno da turma de 50 alunos principal // Declarações inteiro qtde; real nota_1, nota_2, total; inteiro contador; // Instruções qtde = 50; // confirmação da constante com 50 alunos na turma para (contador de 1 ate qtde passo 1) faca escreval("Informe as notas do ", contador, " aluno: "); leia(nota_1); leia(nota_2); total = media(nota_1,nota_2); //chamando a função escreval(""); // saltando duas linhas para apresentar resultado escreva("Média Final = ", total); // lembrando que a apresentação de total:3:1 mostra o valor de total // usando 3 casas numéricas, sendo 2 inteiras e 1 decimal no mínimo fimPara fimPrincipal funcao real media(real num_1, real num_2) real resultado; resultado = ((num_1 + num_2) / 2); retorna (resultado); fimFuncao
Observe no exemplo anterior que existe um subprograma para o algoritmo principal que aciona 50 vezes este mesmo subprograma (função media). Em cada acionamento desta função foram enviados parâmetros com valores possivelmente diferentes, o que resultará em um cálculo de média diferente para cada acionamento.
Um algoritmo em execução deve obedecer a sequência das instruções, a menos que existam comandos (instruções) específicos que alterem esta ordem sequencial (comandos de seleção ou repetição, por exemplo).
Porém, a chamada do subprograma desloca a sequência de execução do algoritmo para o corpo da função que também obedecerá a sequência de execução, respeitando as instruções existentes em seu corpo.
Quando o subprograma (função) chegar ao seu final, ele retornará um único valor para o algoritmo que o acionou, continuando a execução do mesmo a partir da próxima instrução a ser realizada.
Um algoritmo possui uma estrutura bem organizada, onde subprogramas executam tarefas bem determinadas. Esta divisão facilita a legibilidade e a manutenção corretiva e/ou evolutiva sobre os mesmos.
Um subprograma só pode ser acionado pelo algoritmo que o contém, ou seja, que o declara, podendo ele também possuir outros subprogramas.
Todo algoritmo com subprograma deve possuir uma estrutura similar a representada, de forma simples, abaixo:
Síntese do problema |
Declarações |
Algoritmo Principal |
Subprogramas |
Fluxograma:
A representação do subprograma em uma técnica gráfica, como o fluxograma, é apresentado a seguir.
Por meio do nome do subprograma e seus parâmetros, se houverem, o local do acionamento do subprograma é identificado, deslocando a sua execução para um outro fluxograma, o fluxograma do subprograma acionado.
Este outro fluxograma deverá ser elaborado, representando exatamente o que este subprograma executa, ou seja, as tarefas/operações existentes no corpo do subprograma, ou seja, exatamente o que ele realiza após seu acionamento.
As elipses de Início e Fim do algoritmo acionador (principal) são inseridas da mesma forma, porém no diagrama que especifica o corpo da função a elipse inicial é substituída pelo nome do subprograma e sua lista de parâmetros, enquanto que a elipse final contém a palavra reservada retorna e a informação que será retornada.
Um subprograma sempre retorna um valor ao algoritmo que o aciona, por isso ele possui um tipo de dado declarado, retornando ao acionador um dado exatamente deste tipo.
Exemplo:
/// Objetivo: Calcular a média de dois numeros // Parâl;metro: Dois valores que terão sua média calculada // Retorno: Média dos dois numeros funcao real media(real valor_1, real valor_2) //Declarações real resultado; //Instruções resultado = ((valor_1 + valor_2) / 2); retorna (resultado); fimFuncao
A instrução retorna executa o encerramento do subprograma, retornando imediatamente um único valor desejado a instrução acionadora da função. Esta instrução só pode retornar um único valor ao acionador.
Aplicando o processo de modularização, todos os objetos (variáveis ou constantes) pertencem ao contexto em que são declarados e só podem ser utilizadas por quem as declara, ou seja, todos os objetos são locais ao algoritmo principal ou aos sub-algoritmos.
O valor de uma variável declarada no algoritmo principal/sub-algoritmo, pode ser utilizada dentro de um ou mais sub-algoritmos através da passagem de parâmetros.
A criação de sub-algoritmos nem sempre significa que o desenvolvimento do algoritmo irá diminuir o trabalho do programador.
Exemplo
Suponha a leitura de 3 variáveis de tipos diferentes. Neste caso haveria a necessidade da criação de 3 sub-algoritmos, um para cada leitura de cada tipo de variável, no entanto, estes mesmos 3 algoritmos poderiam ser utilizados para a leitura de 100 ou 1000 variáveis diferentes dos três tipos mencionados.
Reutilização de código com aproveitamento da lógica existente no subprograma;
Subprogramas devem ser genéricos o bastante para se adaptarem às diversas situações, visando justamente essa reutilização;
A passagem de parâmetros possibilita o envio de diferentes valores para um mesmo subprograma, que realizará as operações necessárias sobre estes dados;
A passagem de parâmetros pode ocorrer de duas formas
Passagem por valor
Passagem por referência
Subprograma usa uma cópia do valor existente no algoritmo acionador;
Não altera o valor original existente no algoritmo acionador, trabalhando somente sobre o valor local copiado do acionador;
Valor existente no subprograma não pode ser acessado pelo algoritmo principal, a menos que este seja retornado ao algoritmo acionador;
Com a finalização do subprograma, todos os parâmetros e componentes locais são destruídas, ou seja, deixam de existir na memória do computador.
Subprograma usa o valor original existente no algoritmo acionador por meio do acesso ao mesmo endereço de memória;
A manipulação desse tipo de parâmetro altera o valor existente no algoritmo acionador, ou seja, o valor original sofre alteração;
Com a finalização do subprograma o valor do parâmetro passado por referência não é destruído, pois ele alterou o valor original existente no algoritmo acionador.
Consiste em um subprograma iniciado pela palavra reservada procedimento, seguida de um identificador que lhe fornece um nome e sua lista de parâmetros.
Nenhum procedimento possui tipo de dado de retorno, como em uma função, pois este tipo de subprograma não retorna nenhum valor ao seu chamador (acionador).
Como em uma função, sua lista de parâmetros consiste em valores que o algoritmo principal, ou outro subprograma, possui e o procedimento necessita de seus conteúdos para obter ou gerar outro dado importante para o algoritmo alcançar seu êxito.
O acionamento do procedimento também ocorre por meio da especificação do seu nome, seguido da lista de parâmetros a serem manipulados pelo próprio procedimento. No entanto, esta lista tem sua representação opcional ao programador, pois pode não existir nenhum valor do algoritmo que seja necessário a este subprograma.
Um procedimento possui dois momentos no algoritmo:
Primeiro momento é o da declaração, onde é elaborado o cabeçalho da função coerente com as suas necessidades e a descrição das tarefas/operações que ele realizará quando for acionado (seu corpo);
Segundo momento é a utilização ou acionamento do procedimento que pode acontecer várias vezes depois da sua criação e dentro do algoritmo no qual ela também faz parte.
Sintaxe:
// Objetivo: // Parâmetro: // Retorno: Sem retorno. procedimento <identificador>(<lista de parâmetros>) //Desclarações <tipo de dado> <identificador>; //Instruções instrução 1 instrução 2 : instrução n fimProcedimento
onde:
procedimento palavra reservada que identifica este tipo de subprograma;
<identificador> nome atribuído ao procedimento, aos parâmetros e componentes locais quando existirem;
<lista de parâmetros> são os parâmetros usados no procedimento;
<tipo de dado> é um tipo de dado válido (inteiro, real, caracter, texto, lógico).
Os parâmetros de um procedimento são dados fundamentais que este tipo de subprograma deve acessar para realizar seu objetivo. Por exemplo, se você deseja indicar se uma pessoa é "maior de idade" ou não, poderá empregar um procedimento que faça tal identificação, porém este procedimento precisará ter conhecimento da idade desta pessoa. Caso contrário, o procedimento não conseguirá analisar a situação de maioridade da pessoa desejada. Assim, a idade desta pessoa deverá ser disponibilizada ao procedimento por meio da passagem de parâmetros.
Portanto, a estrutura descritiva desse procedimento seria:
// Objetivo: Indicar se a pessoa é alcançou a maioridade // Parâl;metro: Idade da pessoa // Retorno: Sem Retorno. procedimento maioridade(inteiro idadeAuxiliar) //Declarações // sem necessidade da criação de componentes locais //Instruções se (idadeAuxiliar < 18) entao escreva("Indivíduo menor de idade."); senao escreva("Indivíduo maior de idade."); fimSe fimProcedimento
onde: idadeAuxiliar é um parâmetro do procedimento maioridade descrito acima.
Na identificação e descrição das tarefas/operações realizadas pelo procedimento são declaradas suas variáveis, constantes e outros subprogramas internos a este procedimento, ou seja, seus componentes locais. A partir da palavra reservada procedimento inicias-se a elaboração do subprograma (do tipo procedimento) até a expressão fimProcedimento.
Na utilização, também denominada acionamento ou chamada do procedimento, o algoritmo que o declarou pode acioná-lo por meio do seu nome e seus parâmetros, efetuando seu acionamento (ou chamada). Este acionamento é similar à chamada de um amigo que está distante. Para que ele o ouça, você deve chamá-lo pelo seu nome (gritando se ele estiver bem distante). Isso provocará o seu acionamento, onde ele lhe dará mais atenção até descobrir o que você deseja (fornecer as informações desejadas como na passagem de parâmetros).
Exemplo:
O algoritmo a seguir calcula a porcentagem de pessoas aprovados e reprovados em um concurso por meio da função fazPorcentagem e apresenta essas porcentagem por meio do procedimento mostraResultados.
algoritmo porcentagemConcurso;
// Síntese
// Objetivo: fazer a porcentagem de Pessoas aprovadas e reprovadas no Concurso
// Entrada : quantidade de Pessoas aprovadas e quantidade Pessoas reprovadas
// Saída : quantidade de Pessoas avaliadas e procentagem das Pessoas reprovadas e aprovadas
principal
// Declarações
inteiro qtdPessoas,qtdAprovados, qtdReprovados;
real porcenAprovados,porcenReprovados;
// Instruções
escreva("Digite o Numero De Pessoas Aprovadas no Concurso: ");
leia(qtdAprovados);
escreva("Digite o Numero De Pessoas Reprovadas no Concurso: ");
leia(qtdReprovados);
qtdPessoas = qtdAprovados + qtdReprovados;
porcenAprovados = fazPorcentagem(qtdPessoas,qtdAprovados);
porcenReprovados = fazPorcentagem(qtdPessoas,qtdReprovados);
mostraRestultados(qtdPessoas,porcenAprovados,porcenReprovados);
fimPrincipal
//=========SUBALGORITMOS===========
// Objetivo: fazer a porcentagem
// Parâmetro: total e parte
// Retorno: porcentagem
funcao real fazPorcentagem(inteiro total, inteiro parte)
// Instruções
retorna (parte/total)*100;
fimFuncao
// Objetivo: mostar os resutados
// Parâmetro: quantidade de pessoas ,porcentagem de aprovados e de reprovados
// Retorno: sem retorno
procedimento mostraRestultados(inteiro qtdPessoas, real porcenAprovados, real porcenReprovados)
// sem declaração de componente local ao procedimento
// Instruções
escreval(" ");
escreval(" ");
escreval(porcenAprovados::2,"% das Pessoas foram Aprovadas nesse Concurso");
escreval(porcenReprovados::2,"% das Pessoas foram Reprovados nesse Concurso");
escreval(qtdPessoas," Pessoas fizeram o Concurso");
fimProcedimento
Observe no exemplo anterior que existem dois subprogramas no algoritmo principal, sendo cada um deles acionados no momento mais oportuno. Após a leitura do número de aprovados e reprovados e feito o cálculo do total de alunos, a função fazProcentagem é acionada para o cálculo das porcentagens. Em seguida é acionado o procedimento mostraResultados que apresentará o resultado da porcentagem calculada.
É importante observar que foram enviados parâmetros coerentes para os dois subprogramas, o que resultou em um funcionamento correto, de acordo com as quantidades de pessoas fornecidas pelo usuário.
Na solução proposta pelo exemplo acima seria possível informar número de pessoas aprovadas e reprovadas como, 50 e 200 respectivamente , sendo o resultado calculado apresentado na figura abaixo.
No intuito de fixar a aprendizagem iniciada por meio deste módulo e verificar como seu entendimento sobre este conteúdo está, estão sendo sugeridos alguns exercícios de fixação para serem resolvidos. Clique no link de exercícios ao lado, pois será por meio dele iniciada a lista de exercícios sobre os conteúdos estudados até este momento nesta disciplina.