Aula 10 - Modularização e Funções

Subalgoritmos: funções e procedimentos - utilizados para modularizar e subdividir os algoritmos em códigos mais simples e menores.

1 - Subalgoritmos: Funções e Procedimentos

A complexidade dos algoritmos está intimamente ligada à da aplicação a que se destinam. Em geral, problemas complicados exigem algoritmos extensos para sua solução.

Sempre é possível dividir problemas grandes e complicados em problemas menores e de solução mais simples. Assim, pode-se solucionar cada um destes pequenos problemas separadamente, criando algoritmos para tal (subalgoritmos ou subprogramas).

Posteriormente, pela justaposição destes subalgoritmos elabora-se “automaticamente” um algoritmo mais complexo e que soluciona o problema original. Esta metodologia de trabalho é conhecida como Método de Refinamentos Sucessivos, cujo estudo é assunto de cursos avançados sobre técnicas de programação.

Um subalgoritmo é um nome dado a um trecho de um algoritmo mais complexo e que em geral, encerra em si próprio, um pedaço da solução de um problema maior - o algoritmo a que ele está subordinado. Este conceito é essencial em Engenharia de Software.

Também costuma receber os nomes de sub-rotina, procedimento, método ou módulo.

Em resumo, os subalgoritmos são importantes na:

• Subdivisão de algoritmos complexos, facilitando o seu entendimento e implementação;
• Estruturação de algoritmos, facilitando principalmente a detecção de erros e a documentação de sistemas; e
• Modularização de sistemas, que facilita a manutenção de softwares e a reutilização de subalgoritmos já implementados.

A ideia da reutilização de software tem sido adotada por muitos grupos de desenvolvimento de sistemas de computador, devido à economia de tempo e trabalho que proporcionam.

Seu princípio é o seguinte: um conjunto de algoritmos destinados a solucionar uma série de tarefas bastante corriqueiras é desenvolvido, e vai sendo aumentado com o passar do tempo, com o acréscimo de novos algoritmos.

A este conjunto, dá-se o nome de biblioteca. No desenvolvimento de novos sistemas, procura-se ao máximo basear sua concepção em subalgoritmos já existentes na biblioteca, de modo que a quantidade de software realmente novo que deve ser desenvolvido é minimizada.

Muitas vezes os subalgoritmos, podem ser úteis para encerrar em si, uma certa sequência de comandos que é repetida várias vezes num algoritmo. Nestes casos, os subalgoritmos proporcionam uma diminuição do tamanho de algoritmos maiores.

Mecanismo de Funcionamento:

Um algoritmo completo é dividido num algoritmo principal e diversos subalgoritmos (tantos quantos forem necessários e/ou convenientes).

O algoritmo principal é aquele por onde a execução do algoritmo sempre se inicia. Este pode eventualmente invocar os demais subalgoritmos.

O corpo do algoritmo principal é sempre o último trecho do pseudocódigo de um algoritmo. As definições dos subalgoritmos estão sempre colocadas no trecho após a definição das variáveis globais e antes do corpo do algoritmo principal:

ALGORITMO nome do algoritmo

Var

definição das variáveis globais

definições dos subalgoritmos

Inicio

corpo do algoritmo principal

Fimalgoritmo

Durante a execução do algoritmo principal, quando se encontra um comando de invocação de um subalgoritmo, a execução do mesmo é interrompida. A seguir, passa-se à execução dos comandos do corpo do subalgoritmo.

Ao seu término, retoma-se a execução do algoritmo que o chamou (no caso, o algoritmo principal), no ponto onde foi interrompida (comando de chamada do subalgoritmo), e prossegue-se pela instrução imediatamente seguinte.

Note, também, que é possível que um subalgoritmo chame outro subalgoritmo através do mesmo mecanismo.

Definição de Subalgoritmos:

A definição de um subalgoritmo consta de:

• Um cabeçalho, onde estão definidos o nome e o tipo do subalgoritmo, bem como os seus parâmetros e variáveis locais;
• Um corpo, onde se encontram as instruções (comandos), do subalgoritmo;
• O nome de um subalgoritmo é o nome simbólico pelo qual ele é chamado por outro algoritmo;
• O corpo do subalgoritmo contém as instruções que são executadas cada vez que ele é invocado;
• Variáveis locais são aquelas definidas dentro do próprio subalgoritmo e só podem ser utilizadas pelo mesmo.

Parâmetros são canais por onde os dados são transferidos pelo algoritmo chamador a um subalgoritmo, e vice-versa.

Para que possa iniciar a execução das instruções em seu corpo, um subalgoritmo, às vezes, precisa receber dados do algoritmo que o chamou e, ao terminar sua tarefa, o subalgoritmo deve fornecer ao algoritmo chamador os resultados da mesma.

Esta comunicação bidirecional pode ser feita de dois modos que serão estudados mais à frente: por meio de variáveis globais ou por meio da passagem de parâmetros.

A quantidade dos parâmetros, sua sequência e respectivos tipos, não podem mudar: devem estar de acordo com o que foi especificado na sua correspondente declaração.

O tipo de um subalgoritmo é definido em função do número de valores que o subalgoritmo retorna ao algoritmo que o chamou. Segundo esta classificação, os algoritmos podem ser de dois tipos:

• Funções: que retornam um, e somente um, valor ao algoritmo chamador;
• Procedimentos: que retornam zero (nenhum), ou mais valores ao algoritmo chamador.

Na realidade, a tarefa desempenhada por um subalgoritmo do tipo função, pode perfeitamente ser feita por outro do tipo procedimento (o primeiro é um caso particular deste). Esta diferenciação é feita por razões históricas, ou, então, pelo grande número de subalgoritmos que se encaixam na categoria de funções.

Escute essa aula: Subalgoritmos

Funções:

O conceito de Função é originário da ideia de função matemática (por exemplo, raiz quadrada, seno, cosseno, tangente, logaritmo, entre outras), onde um valor é calculado a partir de outro(s) fornecido(s) à função.

Em VisuAlg, função é um subprograma que retorna um valor. Sua declaração deve estar entre o final da declaração de variáveis e a linha início do programa principal, e segue a sintaxe abaixo:

funcao nome-de-função [(sequência-de-declarações-de-parâmetros)]:

// Seção de Declarações de variáveis Internas/locais

inicio

// Seção de Comandos

Fimfuncao

Temos que:

• Nome-de-função: é o nome simbólico pelo qual a função é invocada por outros algoritmos;
• Parâmetros: são os parâmetros da função;
• Tipo de dado: é o tipo de dado da informação retornado pela função ao algoritmo chamador;
• Variáveis internas locais: consiste na definição das variáveis locais à função. Sua forma é análoga à da definição de variáveis num algoritmo;
• Seção de Comandos: é o conjunto de instruções do corpo da função.

A invocação de uma função é feita pelo simples aparecimento do nome da mesma, seguido pelos respectivos parâmetros entre parênteses, dentro de uma expressão. A função é executada e, ao seu término, o trecho do comando que a invocou é substituído pelo valor retornado pela mesma dentro da expressão em que se encontra, e a avaliação desta prossegue normalmente.

Dentro de uma função, e somente neste caso, o comando Retorne (expressão), é usado para retornar o valor calculado pela mesma.

Ao encontrar este comando, a expressão entre parênteses é avaliada, a execução da função é terminada neste ponto e o valor da expressão é retornado ao algoritmo chamador.

Vale lembrar que uma expressão pode ser uma simples constante, uma variável ou uma combinação das duas por meio de operadores. Esta expressão deve ser do mesmo tipo que o valor retornado pela função.

Exemplo1:

Função sem parâmetros.

funcao soma: inteiro

var aux: inteiro

inicio

// n, m e res são variáveis globais
aux := n + m
retorne aux

fimfuncao

Esta função cria uma variável local chamada aux, então ela recebe os valores de m e n (que são variáveis globais), e então retorna o valor de aux (que agora é a soma de m e n), para o algoritmo principal.

Veja e execute o algoritmo no VisuAlg:

algoritmo "funcao_soma_sem_parametros"

var //declaração das variaveis globais

m, n, res :inteiro

funcao soma: inteiro

var aux: inteiro //declaração das variaveis locais

inicio

// n, m e res são variáveis globais
aux := n + m
retorne aux

fimfuncao

inicio // início do algoritmo principal

escreval ("digite o primeiro valor")
leia (m)
escreval ("digite o segundo valor")
leia (n)
res:=soma //chamada da função sem parâmetros
escreval ("o valor da soma dos valores é: ",res)

fimalgoritmo

Veja uma possível saída do algoritmo:

Escute essa aula: Funções Sem Parâmetros

Agora veja a mesma função com a passagem de parâmetros:

Exemplo 2:

Função com parâmetros

algoritmo "funcao_soma_COM_parametros"

var //declaração das variaveis globais

m, n, res:inteiro

funcao soma (x,y: inteiro): inteiro

inicio

retorne x+y

fimfuncao

inicio // início do algoritmo principal

escreval ("digite o primeiro valor")
leia (m)
escreval ("digite o segundo valor")
leia (n)
res:=soma(m,n) //chamada da função com parâmetros
escreval ("o valor da soma dos valores é: ",res)

fimalgoritmo

Observe que a ordem dos parâmetros é importante, neste exemplo temos a chamada da função soma passando os parâmetros da seguinte forma: soma(m,n) .

Na declaração da função temos: funcao soma (x,y: inteiro): inteiro.

Portanto, na substituição dos valores por parâmetros, a variável x passará a ter o valor armazenado na variável m e a variável y passará a ter o valor armazenado na variável n.

Observe no seguinte GIF, o fluxo do algoritmo sendo direcionado para a função quando ela é chamada, e a criação das variáveis locais x e y, pertencentes apenas a função soma.

Escute essa aula: Funções Com Parâmetros

Exemplo 3:

O algoritmo a seguir é um exemplo do emprego de função para calcular o valor de um número elevado ao quadrado.

algoritmo "funcao_quadrado_COM_parametros"

var //declaração das variaveis globais

x, y :real

funcao Quadrado (z: real): real

var

w:real

inicio

w:=z*z
retorne w

fimfuncao

inicio // início do algoritmo principal

escreval ("digite o valor para calcular seu quadrado")
leia (x)
y:= Quadrado(x)
escreval (x," elevado ao quadrado é: ",y)

fimalgoritmo

Veja uma possível saída para o algoritmo:

Escute essa aula: Funções Com Parâmetros 2

Procedimentos:

Um procedimento é um subalgoritmo que retorna zero (nenhum), ou mais valores ao subalgoritmo chamador.

Estes valores são sempre retornados por meio dos parâmetros ou de variáveis globais, mas nunca explicitamente, como no caso de funções, ou seja, não possuem o comando retorne. Portanto, a chamada de um procedimento nunca surge no meio de expressões, como no caso de funções.

Pelo contrário, a chamada de procedimentos só é feita em comandos isolados dentro de um algoritmo, como as instruções de entrada (Leia), e saída (Escreva), de dados.

Sua declaração, que deve estar entre o final da declaração de variáveis globais e a linha início do programa principal, segue a sintaxe abaixo:

procedimento nome-de-procedimento [(sequência-de-declarações-de-parâmetros)]

// Seção de Declarações Internas

inicio

// Seção de Comandos

fimprocedimento

Temos que:

• nome-de-procedimento: é o nome simbólico pelo qual o procedimento é invocado por outros algoritmos;
• parâmetros: são os parâmetros do procedimento;
• variáveis locais: são as definições das variáveis locais ao procedimento. Sua forma é análoga à da definição de variáveis num algoritmo;
• Seção de Comandos: é o conjunto de instruções do corpo do procedimento, que é executado toda vez que o mesmo é invocado.

Um procedimento é chamado/invocado de forma análoga as funções, uma diferença é que como o procedimento não retorna um valor diretamente, não é preciso declarar o seu tipo como nas funções.

Exemplo 1:

Procedimento de soma sem parâmetros:

algoritmo "procedimento_soma_sem_parametros"

var //declaração das variaveis globais

m, n, res:inteiro

procedimento soma

var

aux: inteiro //declaração de variaveis locais

inicio

aux:= n+m
res:=aux
escreval ("o valor da soma dos valores é: ",res)

fimprocedimento

inicio // início do algoritmo principal

escreval ("digite o primeiro valor")
leia (m)
escreval ("digite o segundo valor")
leia (n)
soma //chamada do procedimento

fimalgoritmo

Veja uma possível saída do algoritmo:

Observe, que o procedimento ficou responsável por somar os dois valores digitados no programa principal (variáveis globais), e imprimir o seu resultado na tela.

Escute essa aula: Procedimentos Sem Parâmetros

Da mesma forma, o procedimento poderia ter sido executado através de um procedimento com passagem de parâmetros

Exemplo 2:

Procedimento de soma com parâmetros:

algoritmo "procedimento_soma_COM_parametros"

var //declaração das variaveis globais

m, n, res:inteiro

procedimento soma(x,y:inteiro)

inicio

res:=x+y
escreval ("o valor da soma dos valores é: ",res)

fimprocedimento

inicio // início do algoritmo principal

escreval ("digite o primeiro valor")
leia (m)
escreval ("digite o segundo valor")
leia (n)
soma(m,n) //chamada do procedimento

fimalgoritmo

Observe que o procedimento recebe como parâmetros os valores digitados pelo usuário, no programa principal, e estes valores são atribuídos às variáveis x e y, então, é realizada a operação e o resultado é mostrado na tela.

Escute essa aula: Procedimentos Com Parâmetros

O exemplo a seguir é um exemplo simples, onde um procedimento é usado para ler e escrever o valor das componentes de um vetor.

Exemplo 3:

algoritmo "procedimentos_de_vetor"

var

vet:vetor[1..5] de inteiro
i : inteiro

procedimento LeitorVetor

inicio

Para i de 1 ate 5 faca

escreval ("digite o valor para a posição ", i)
leia (vet[i])

fimpara

fimprocedimento

procedimento EscreveVetor

inicio

Para i de 1 ate 5 faca

escreval ("o valor na posição: ",i , " é ",vet[i])

fimpara

fimprocedimento

inicio

LeitorVetor
EscreveVetor

Fimalgoritmo

Veja uma possível saída do algoritmo:

Observe, que o algoritmo principal apenas chama os procedimentos, agora reflita, em como os procedimentos podem otimizar um algoritmo.

Toda vez que o usuário precisar ler ou escrever um vetor, basta apenas chamar o procedimento, não sendo necessário escrever todos os comandos novamente.

Observe no seguinte GIF, o fluxo do algoritmo sendo alterado para os procedimentos quando chamados.

Escute essa aula: Procedimentos Vetor

Passagem de Parâmetros por Referência:

Há ainda, uma outra forma de passagem de parâmetros para subprogramas: é a passagem por referência. Neste caso, o subprograma não recebe apenas um valor, mas sim o endereço de uma variável global.

Portanto, qualquer modificação que for realizada no conteúdo deste parâmetro afetará também a variável global que está associada a ele. Durante a execução do subprograma, os parâmetros passados por referência são análogos às variáveis globais.

No VisuAlg, essa passagem é feita através da palavra var na declaração do parâmetro. Voltando ao exemplo da soma, o procedimento abaixo, realiza a mesma tarefa, utilizando passagem de parâmetros por referência:

procedimento soma (x,y: inteiro; var result:inteiro)

inicio

result:=x+y

fimprocedimento

Exemplo:

algoritmo "procedimento_soma_Pasagem_por_referencia

var //declaração das variaveis globais

m, n, res:inteiro

procedimento soma (x,y: inteiro; var result:inteiro)

inicio

result:=x+y

fimprocedimento

inicio // inicio do algoritmo principal

escreval ("digite o primeiro valor")
leia (m)
escreval ("digite o segundo valor")
leia (n)
soma(m,n,res) //chamada da função com parâmetros e referência
escreval ("o valor da soma dos valores é: ",res)

fimalgoritmo

Neste exemplo, a variável res do algoritmo principal, foi passada por referência como parâmetro da variável result do procedimento soma, portanto qualquer modificação a variável result, modificará a variável res no algoritmo principal.

Escute essa aula: Passagem de Parâmetros por Referência

Recursão e Aninhamento:

A atual versão do VisuAlg permite recursão, isto é, a possibilidade de que um subprograma possa chamar a si mesmo. A função do exemplo abaixo calcula recursivamente o fatorial do número inteiro que recebe como parâmetro:

funcao fatorial (v: inteiro): inteiro

inicio

se v <= 2 entao

retorne v

senao

retorne v * fatorial(v-1)

fimse

fimfuncao

A seguir um algoritmo exemplo que utiliza esta função:

Exemplo1:

algoritmo "fatorial_recursivo"

var

fat,num: inteiro

funcao fatorial (v: inteiro): inteiro

inicio

se v <= 2 entao

retorne v

senao

retorne v * fatorial(v-1)

fimse

fimfuncao

inicio

escreval ("digite um valor para calcular seu fatorial")
leia(num)
fat:=fatorial(num)
escreval ("o valor do fatorial de: ",num," é: ",fat)

fimalgoritmo

Obseve no seguinte GIF, o fluxo do algoritmo sendo alterado para a função e as variáveis locais sendo criadas a cada chamada da função.

Escute essa aula: Recursão e Aninhamento

Links Úteis

Canal: Prime Cursos do Brasil

Site: Manual do VisuAlg 3.0

Referências

  • CORMEN, Thomas H. et al. Algoritmos: teoria e prática. Editora Campus, v. 2, p. 296, 2002.
  • FARRER, Harry; BECKER, Christiano Gonçalves. Algoritmos estruturados: programação estruturada de computadores. Rio de Janeiro: Guanabara, 2000.
  • NETO, Benedito; PEREIRA, Diego; FERNANDES, Sabrina. Apostila de Algoritmo - CEP - Centro De Educação Profissional "Tacredo Neves".
  • Manual do VisuAlg 3.0