Funções e Procedimentos



Documentos relacionados
Programação de Computadores I. Linguagem C Função

Estruturas de Repetição

Programação de Computadores I Estruturas de Repetição PROFESSORA CINTIA CAETANO

Linguagens de Programação:

Nº horas ESTRATÉGIAS RECURSOS AVALIAÇÃO

Parte 05 - Técnicas de programação (mapas de Veitch-Karnaugh)

Algoritmos e Programação : Conceitos e estruturas básicas. Hudson Victoria Diniz

Os conceitos aprendidos são fundamentais, essenciais para escrever um programa macro. Mas o que é um programa macro?

2) Escreva um algoritmo que leia um conjunto de 10 notas, armazene-as em uma variável composta chamada NOTA e calcule e imprima a sua média.

3. COMPILAÇÃO E ESTRUTURA BÁSICA DE UM PROGRAMA EM C

Programação. Folha Prática 4. Lab. 4. Departamento de Informática Universidade da Beira Interior Portugal Copyright 2010 All rights reserved.

FOLHA DE CÁLCULO ELABORAÇÃO DE GRÁFICOS

Ciclo com Contador : instrução for. for de variável := expressão to. expressão do instrução

INTRODUÇÃO À PROGRAMAÇÃO EM FORTRAN

Área Reservada do Beneficiário da ADM Informação em Tempo Real.

Algoritmo e Pseudo-código

Orientação a Objetos

Comandos de Desvio 1

Metodologias de Programação

Escalas ESCALAS COTAGEM

Algoritmos e Estruturas de Dados I. Variáveis Indexadas. Pedro O.S. Vaz de Melo

1. Noção de algoritmo

FUNÇÕES MATEMÁTICAS NÚMERO : PI() SENO E COSSENO: SEN() E COS()

AULA 3 Alocação dinâmica de memória: Ponteiros

Tipos de problemas de programação inteira (PI) Programação Inteira. Abordagem para solução de problemas de PI. Programação inteira

Módulo IV Programação Visual Basic. Programação

Introdução à Programação. Funções e Procedimentos. Prof. José Honorato F. Nunes honoratonunes@gmail.com

Exercícios: Recursão

INF1005: Programação I. Algoritmos e Pseudocódigo

Conceitos básicos de programação

Algoritmos e Estruturas de Dados I. Recursividade. Pedro O.S. Vaz de Melo

Lição 5 Medidas Descritivas Medidas de Dispersão

OBSERVAÇÕES: EXERCÍCIOS

Normas para a elaboração de um relatório. para a disciplina de projecto integrado. 3.º ano 2.º semestre. Abril de 2004

COTAÇÕES pontos pontos. 52 pontos. 48 pontos. 16 pontos Subtotal pontos. TOTAL pontos

Teoria de Jogos. Algoritmo Minimax e Alfa-Beta AED

Teoria dos Grafos. Valeriano A. de Oliveira Socorro Rangel Departamento de Matemática Aplicada.

Exame de Equivalência à Frequência do Ensino Secundário

Lista 4 Introdução à Programação Entregar até 07/05/2012

2ª Lista de Exercícios

Exercícios: Vetores e Matrizes

- Campus Salto. Disciplina: Sistemas de Arquivos Docente: Fernando Santorsula

alocação de custo têm que ser feita de maneira estimada e muitas vezes arbitrária (como o aluguel, a supervisão, as chefias, etc.

Índice. Para que efeito deve ser usada cada operação de certificação? Qual o período de referência das operações de certificação?

Teste de Funções por Cobertura do Grafo de Fluxo de Controle

Microsoft Excel INTRODUÇÃO PARTE 1 SUMÁRIO

Prova Modelo. Nome: Número:

Parabéns pela escolha do cartão TOURS.

EXAME NACIONAL DO ENSINO SECUNDÁRIO

Circuitos Aritméticos

22 SET Área Cliente. Manual do Utilizador

Universidade Federal de Uberlândia - UFU Faculdade de Computação - FACOM Lista de exercícios de programação em linguagem C. Exercícios: Structs

1.2. Grandezas Fundamentais e Sistemas de Unidades

SOLUÇÕES N item a) O maior dos quatro retângulos tem lados de medida 30 4 = 26 cm e 20 7 = 13 cm. Logo, sua área é 26 x 13= 338 cm 2.

Escola Secundária c/3º CEB José Macedo Fragateiro. Curso Profissional de Nível Secundário. Componente Técnica. Disciplina de

PROVA Duração da prova: 120 minutos

M A N U A L D O ADMINISTRADOR DO PORTAL

1. Estrutura de Dados

Placas Gráficas. Placas Gráficas. Placas Gráficas. Placas Gráficas. O que é? Para que serve? Resolução (cont.) Resolução

ÍNDICE GIRA VOLEI REGRAS DE JOGO CAPÍTULO I FUNDAMENTOS E REGRAS DO JOGO. REGRA 1 Terreno de jogo (figs. 1 e 2) 1.1 Superfície de jogo. 1.

Fevereiro 2013 v1.3/dbg

SEQUÊNCIA DIDÁTICA PODCAST ÁREA CIÊNCIAS DA NATUREZA FÍSICA - ENSINO MÉDIO

PROGRAMAÇÃO DE COMPUTADORES I - BCC Lista de Exercícios do Módulo 1 - Preparação para a Prova 1

ANEXO EXCEL 2007 AVAÇADO

Introdução à Algoritmos. Aula 11

MEMÓRIA DESCRITIVA. PROJECTO DE ARQUITECTURA Equipamento com função de apoio de praia

A primeira coisa ao ensinar o teorema de Pitágoras é estudar o triângulo retângulo e suas partes. Desta forma:

Ficheiros binários 1. Ficheiros binários

Universidade Paulista

INFORMÁTICA PARA GESTÃO II Curso Superior de Gestão de Marketing

INSTITUTO SUPERIOR TÉCNICO Análise e Síntese de Algoritmos. RESOLUÇÃO DA RESPESCAGEM DO 2 o TESTE

Matemática Aplicada às Ciências Sociais

Polinômios. Para mais informações sobre a história de monômios e polinômios, leia o artigo Monômios.

Versão 1. Identifica, claramente, na folha de respostas, a versão do teste (1 ou 2) a que respondes.

4 A Ferramenta Computacional

AC05 Lista de Exercícios sobre Sequências, Condições e Repetição Em C++

Documento Geral Explicativo. GS1 Portugal

Solução da prova da 2a fase OBMEP 2014 Nível 2. Questão 1. item a)

MANUAL DE UTILIZAÇÃO DO AUTO ATENDIMENTO SETOR PÚBLICO DO BANCO DO BRASIL

Recursos-chave para Gestores de Projecto Guia 3 Pensamento Crítico Auto-estudo Para o Gestor de Projecto

1. Números. MatemáticaI Gestão ESTG/IPB Departamento de Matemática. Números inteiros. Nota: No Brasil costuma usar-se: bilhão para o número

Exercícios de Fixação Aulas 05 e 06

1. Escreva um programa em Pascal que leia três valores inteiros e mostre-os em ordem crescente. Utilize seleção encadeada.

Produção de documentos acessíveis com Microsoft Word. Gabinete para a Inclusão (GPI)

Calculando seno(x)/x com o interpretador Hall.

(1, 6) é também uma solução da equação, pois = 15, isto é, 15 = 15. ( 23,

Até o momento, vimos que a estrutura de um computador segue uma seqüência: ENTRADA => PROCESSAMENTO => SAÍDA

Árvores Parte 1. Aleardo Manacero Jr. DCCE/UNESP Grupo de Sistemas Paralelos e Distribuídos

Módulo de Catalogação e Pesquisa

PLANEJAMENTO SIMPLIFICADO DE PROJETOS

Erros e Incertezas. Rafael Alves Batista Instituto de Física Gleb Wataghin Universidade Estadual de Campinas (Dated: 10 de Julho de 2011.

Recursos Humanos Recursos Humanos 2007

PLANEJAMENTO E MODELAGEM

Exercícios: comandos de repetição

TOM, SEMITOM, SUSTENIDO, BEMOL.

UNIPAC Araguari FACAE - Faculdade de Ciências Administrativas e Exatas SISTEMAS DE INFORMAÇÃO

Manual de Utilizador Portal de Formação RE/MAX v4.0

CURSO DE MOLDES EM MÓDULOS OU COMPLETO

Unidade 10 Análise combinatória. Introdução Princípio Fundamental da contagem Fatorial

Transcrição:

Funções e Procedimentos 1 Funções e Procedimentos Uma técnica aconselhada para desenvolver bons programas de computador consiste em dividir o problema inicial em subproblemas mais simples ou, por outras palavras, dividir o programa que permite a resolução computacional do problema em subprogramas. É possível encontrar subprogramas de dois tipos: as funções e os procedimentos. Qualquer um deles é uma peça importante para o desenvolvimento de programas de computador, especialmente quando esses programas se destinam à resolução de problemas complexos. Um subprograma constitui um bloco independente dentro de um programa, podendo ser visto como um programa dentro de outro programa. Tal como um programa necessita de comunicar com o ambiente exterior, através da leitura de dados e da apresentação de resultados, também um subprograma deve ter capacidade de aceitar valores e de, eventualmente, devolver resultados ao ambiente em que se insere, ou seja, o programa ou subprograma que controla a sua execução. Utilização de Subprogramas Na escrita de um programa de computador surge muitas vezes a necessidade de repetir a mesma sequência de instruções em locais diferentes do programa. Para evitar esta repetição, que implica um aumento do número de linhas e um tempo de desenvolvimento maior, muitas linguagens de programação apresentam o conceito de subprograma. Este conceito, por vezes também designado por subrotina, permite escrever um conjunto de instruções da linguagem identificadas por um nome determinado. Assim, em vez de repetir as instruções sempre que estas fossem necessárias no programa, bastaria indicar o nome do subprograma correspondente a essas linhas nos locais onde a sequência seria repetida. Um subprograma é controlado por um programa de nível superior que determina quando e sob que condições o subprograma deve ser executado e que pode eventualmente recolher um valor devolvido por este. Os subprogramas podem ser chamados a partir de várias zonas do programa e sob condições diferentes. O seu uso introduz também uma maior flexibilidade no processo de desenvolvimento de software pois permite a substituição fácil de um subprograma por uma versão mais actual. A divisão em subprogramas corresponde à divisão de um problema em subproblemas mais simples o que facilita a resolução do problema inicial e permite uma abordagem Top-down cujas vantagens já foram discutidas. A utilização de subprogramas é também uma forma de facilitar a produção de software favorecendo o recurso a módulos previamente desenvolvidos e constituídos por conjuntos de subprogramas. A utilização destes módulos evita a reescrita de subprogramas sempre que um novo

2 programa necessita de as utilizar, diminuindo o tempo de desenvolvimento de programas complexos e evitando que o programador se preocupe com detalhes pouco importantes para a compreensão do problema. Estes módulos são designados por bibliotecas. Os subprogramas são normalmente classificados como funções ou como procedimentos. Em qualquer subprograma é também possível a definição de outros subprogramas. Alguns deles apresentam ainda uma característica importante e que consiste na possibilidade de se chamarem a si próprios, ou seja, um subprograma é invocado recursivamente pelo mesmo subprograma. Argumentos e Parâmetros Muitas vezes é necessário indicar explicitamente ao subprograma as condições sob as quais a sua execução vai ser realizada. Por estas razões, um subprograma poderá aceitar argumentos que determinam essas condições. Os argumentos poderão ser variáveis, constantes ou expressões. Na descrição do subprograma terão de estar definidos, por sua vez, os parâmetros que correspondem aos argumentos que o programa do nível acima determinou. Estas considerações são válidas quer para subprogramas definidos pelos programadores quer para subprogramas pré-definidos. Considere-se, por exemplo, um subprograma, designado por área(), para calcular a área de um rectângulo, dados os comprimentos dos lados. Este subprograma irá devolver o valor da área do rectângulo. O subprograma seria invocado recorrendo a uma instrução do tipo a = área( comprimento, largura ); A variável a seria de um tipo compatível com o valor de retorno do subprograma e comprimento e largura seriam variáveis usadas como argumentos. O subprograma seria definido como real área( x, y ) real x, y; real z; z = x * y; retorna z; No subprograma área() estão definidos os parâmetros x e y do tipo real. Os parâmetros declaramse imediatamente antes da chaveta que marca o início do conjunto de instruções que constituem a função ou procedimento. Existe uma relação directa entre os argumentos usados na chamada de um subprograma e os parâmetros definidos para esse subprograma. A esses parâmetros irão ser atribuídos os valores dos argumentos. Se o subprograma fosse invocado como

Funções e Procedimentos 3 a = área( 10, 5 ); os parâmetros x e y passariam a conter os valores 10 e 5, respectivamente. Note-se que não tem de existir nenhuma correspondência entre os nomes das variáveis definidas como parâmetros de um subprograma e os nomes de eventuais variáveis usadas como argumentos na chamada desse subprograma. Aliás, no exemplo anterior, o subprograma foi invocado com valores constantes. Outra possibilidade é a utilização de expressões com significado dentro do programa a partir do qual o subprograma é executado. Por exemplo, a = área( x * 2, largura / 10 ); Neste caso, a variável x usada na expressão correspondente ao primeiro argumento, tem um significado diferente do parâmetro x usado da definição do subprograma, embora os nomes sejam iguais. É importante que fique desde já bem clara a distinção entre estas situações. Figura 6.1. Relação entre Argumentos, Parâmetros e Valor de Retorno do Subalgoritmo área(). Funções A secção anterior apresentou uma característica importante: o subprograma área() possui um valor de retorno, ou seja, devolve um valor determinado que pode ser utilizado pelo programa que o invocou. Os subprogramas que apresentam esta característica designam-se por funções. As funções podem ser definidas com ou sem parâmetros. real quadrado( x ) real x; x = x * x; retorna x; programa() real número, resultado; lógico fim = falso;

4 enquanto fim == falso faça leia( número ); se número == 0 então fim = verdadeiro; senão resultado = quadrado( número ); escreva("quadrado de ", número, " é ", resultado); Programa 6.1. Cálculo do Quadrado de um Número Real. As funções, na linguagem PE, incluem sempre a palavra retorna, seguida do valor a devolver ou de uma expressão que defina esse valor. Nas funções é também necessário indicar o tipo do valor de retorno. A linha real quadrado( x ) indica uma função designada por quadrado() que aceita um parâmetro x e retorna um valor real. Genericamente, na linguagem PE, a sintaxe para definição de uma função é a seguinte <tipo valor de retorno> <nome da função>([<lista de parâmetros>]) [<declaração de parâmetros>] <corpo da função> retorna <expressão>; A lista de parâmetros e declarações respectivas são opcionais. Figura 6.2. Exemplo de Definição de uma Função. Procedimentos

Funções e Procedimentos 5 Os procedimentos são subprogramas que se distinguem das funções pelo facto de não apresentarem qualquer valor de retorno. Os procedimentos, tal como as funções, podem apresentar ou não uma lista de parâmetros que definem a forma como o procedimento irá ser executado. Tal como nas funções, é necessário declarar os parâmetros do procedimento no caso de estes existirem. Por exemplo, considere-se o programa 6.1 que permite o cálculo da área de um rectângulo, escrevendo o valor calculado. Neste programa foram definidos dois subprogramas: a função área() que permite o cálculo da área do rectângulo e o procedimento escreve_área() que apresenta o resultado calculado. O programa termina se for introduzido um valor negativo para o comprimento de um lado do rectângulo. real área( x, y ) real x, y; real z; z = x * y; retorna z; escreve_área( área ) real área; escreve( "O valor da área é : ", área ); programa() real x, y, a; lógico fim = falso; repita leia( x ); leia( y ); se x < 0 ou y < 0 então fim = verdadeiro; senão a = área( x, y ); escreve_área( a );

6 até fim == verdadeiro Programa 6.2. Cálculo da Área de Rectângulos: Exemplo da Utilização de Funções e Procedimentos. Note-se que as funções e procedimentos que eventualmente possam existir num programa em PE são sempre definidos antes do procedimento especial programa(). Na linguagem PE, a sintaxe para definição de um procedimento é a seguinte: <nome do procedimento> ( [<lista de parâmetros>] ) [<declaração de parâmetros>] <corpo do procedimento> Tal como no caso das funções, a lista de parâmetros e declarações respectivas são opcionais. Âmbito de Variáveis As variáveis que representam o comprimento dos lados de um rectângulo no programa 6.1 têm o mesmo nome no programa principal e na função área(). Que aconteceria se a função área() alterasse os valores destas variáveis? Os novos valores seriam reconhecidos no programa principal, ou este consideraria apenas os valores iniciais? Na realidade, em ambos os casos, as variáveis são locais, ou seja, são variáveis que são reconhecidas apenas nas funções onde se encontram declaradas. Assume-se que o computador cria novas variáveis em cada um dos casos e as armazena em locais diferentes embora os nomes sejam iguais. Desta forma evitam-se conflitos entre os valores armazenados nas duas situações. Quando termina uma função ou procedimento as suas variáveis locais são destruídas e o espaço de memória respectivo é libertado, podendo ser usado pelo programa para outros fins. Uma variável local só é reconhecida no subprograma em que se encontra declarada, não podendo ser invocada por outros subprogramas. O uso de variáveis locais diminui o espaço na memória do computador requerido por um programa, uma vez que apenas possuem uma área de memória reservada durante a execução do bloco do programa no qual se encontram definidas. Existem, no entanto, muitas situações em que é importante que uma dada variável seja reconhecida em qualquer ponto do programa. Isto significa que, independentemente da função ou procedimento que utilizar a variável, esta estará sempre associada à mesma posição de memória, não sendo destruída depois de ser utilizada por um subprograma. A variável existirá, permanecendo reservado o espaço de memória respectivo, até que o programa termine a sua execução. Assim, é possível considerar a existência de variáveis com características distintas: as variáveis locais ou automáticas que apenas têm existência

Funções e Procedimentos 7 dentro do subprograma em que se encontram declaradas e as variáveis globais ou estáticas que existem enquanto o programa não terminar, sendo reconhecidas por qualquer subprograma. As variáveis globais são declaradas fora de qualquer função ou procedimento, incluindo o procedimento especial programa(). Argumentos de Subprogramas Um subprograma definido de forma a aceitar parâmetros, cria cópias das variáveis passadas como argumentos pelo programa que invocou o subprograma em questão. Isto significa que os parâmetros definidos para um subprograma irão funcionar como variáveis locais desse subprograma. É por este motivo que não existe qualquer conflito em invocar um subprograma cujos argumentos são variáveis com nomes iguais aos parâmetros definidos para o subprograma. Internamente, o computador irá reservar áreas de memória diferentes para os seus parâmetros. Considere-se, por exemplo, o procedimento seguinte: soma_um( x ) inteiro x; x = x + 1; escreva( x ); Este procedimento limita-se apenas a aceitar um valor inteiro, somar o valor 1 ao valor recebido e escrever o resultado. Se este procedimento for chamado em conjunto com as instruções x = 3; soma_um( x ); escreva( x ); o resultado obtido seria 4 3 Conforme o exemplo demonstra, o procedimento soma_um() não alterou o valor da variável x que continuou a ter o valor 3 após a chamada do procedimento. O valor 4 corresponde ao valor da variável x no procedimento soma_um(). Este mecanismo de cópia dos argumentos para variáveis locais no subprograma não é desejável em todas as situações. Existem muitos casos em que se pretende que as alterações exercidas sobre as

8 variáveis correspondentes aos parâmetros do subprograma sejam reconhecidas no programa ou subprograma de nível superior. Um exemplo típico consiste na definição de um subprograma que permita proceder à troca dos valores de duas variáveis. Um procedimento capaz de executar esta tarefa poderia ser troca( a, b ) inteiro a, b; inteiro c; c = a; a = b; b = c; Com este procedimento pretende-se atribuir à variável a o conteúdo da variável b e a esta o conteúdo de a recorrendo a uma variável auxiliar c. Se este procedimento fosse invocado na forma x = 5; y = 6; troca( x, y ); escreva( "x = ", x, " y = ", y ); O resultado obtido seria x = 5 y = 6; ou seja, não houve qualquer troca dos valores das variáveis. A explicação é simples: O procedimento troca() ao ser invocado criou cópias dos argumentos que recebeu, trocou esses valores entre si e, ao terminar, libertou o espaço reservado para os parâmetros que continham o valor dos argumentos. Isto significa que o procedimento funcionou mas apenas em relação às cópias dos argumentos que recebeu. O problema resolve-se se em vez de passar como argumentos os valores das variáveis se indicar ao procedimento troca() as posições de memória (endereços) ocupadas por essas variáveis. Na prática isto significa que os parâmetros do procedimento são substituídos pelos argumentos que são passados, levando a que as alterações efectuadas dentro do procedimento sejam reconhecidas no programa que o invocou. Neste caso diz-se que os argumentos foram passados por referência. A situação inicial corresponde a passar os argumentos por valor. Na linguagem PE a distinção entre estas duas situações é feita através da colocação do carácter & antes do nome do argumento que é passado por referência na instrução correspondente à chamada do procedimento. O carácter & permite aceder ao endereço da variável e não ao seu conteúdo.

Funções e Procedimentos 9 A troca correcta de valores das duas variáveis teria de ser efectuada indicando o endereço dos argumentos do procedimento troca(), ou seja troca( &x, &y ); De igual modo, no exemplo que usava o procedimento soma_um(), a passagem de valores por referência, na forma x = 3; soma_um( &x ); escreva( x ); teria como resultado 4 4 Neste caso, as alterações efectuadas no procedimento foram reconhecidas no programa que o invocou. Em relação a esta questão é importante referir que estes problemas podem ser resolvidos de outra maneira. Para tal basta que as variáveis envolvidas sejam definidas como variáveis globais, sendo reconhecidas em todo o programa. Assim, não seria necessário fazer a passagem de argumentos por referência, aliás, não seria sequer necessário passar essas variáveis como argumentos aos subprogramas que actuassem sobre elas, pois todos os subprogramas são capazes de reconhecer variáveis globais. Este processo não é, no entanto, muito aconselhável, uma vez que limita as potencialidades de utilização dos subprogramas, que passam a ter um carácter muito restrito. As linguagens de programação apresentam formas diversas de efectuar a distinção entre a passagem de argumentos por valor ou por referência. Na linguagem PE optou-se por usar um processo de distinção dos dois casos que se aproxima de certa forma daquilo que se passa na linguagem C. Recursividade Os subprogramas podem invocar livremente outros subprogramas sendo esta possibilidade usada para a subdivisão de tarefas de um programa. Para além desta facilidade, qualquer subprograma pode-se chamar a si próprio de uma forma recursiva. A escrita de subprogramas recursivos permite encontrar boas soluções para certos tipos de problemas particulares que, de outra forma, implicariam maior número de instruções e maior dificuldade de compreensão do objectivo a atingir. Existem muitos exemplos típicos de algoritmos recursivos. Considere-se então um subprograma recursivo para o cálculo da expressão x n, na qual x e n são números inteiros e n é positivo. Este

10 subprograma irá tirar partido de uma definição particular da potência de um número, na qual a expressão x n é representada por potência( x, n): potência( x, n ) = x, se n = 1 potência( x, n ) = x * potência( x, n - 1 ), se n > 1 A função potência é, neste caso, definida à custa de si própria. Em linguagem PE, esta função seria escrita conforme se apresenta no programa 6.3. inteiro potência( x, n ) inteiro x, n; se n == 1 então retorna x; senão retorna x * potência( x, n - 1 ); Programa 6.3. Função Recursiva para Cálculo da Potência de um Número Inteiro. De acordo com a função potência(), o cálculo é efectuado através de chamadas recursivas da função com o parâmetro n a ser decrementado de uma unidade em cada nova chamada da função. Quando esta for invocada com o valor 1 para o parâmetro n, a função retorna o valor do parâmetro x. O valor final é então calculado à medida que vão sendo retornados valores correspondentes às diversas chamadas da função potência(). Por exemplo, uma chamada da função com os valores 2 e 3 para os parâmetros x e n, respectivamente, originaria a sequência potência( 2, 3 ) 2 * potência( 2, 2 ) 2 * 2 * potência( 2, 1 ) A função ao ser invocada com o valor 1 para o parâmetro n, termina a série de chamadas recursivas e retorna o valor do parâmetro x, ou seja, 2. A expressão final que a ser calculada calculada é 2 * 2 * 2 e a função retorna o valor 8. Esta função foi apresentada apenas com o objectivo de exemplificar a utilização de uma função recursiva, uma vez que, na linguagem PE, existe definido o operador potenciação ( ^ ).

Funções e Procedimentos 11 O cálculo do factorial de um número inteiro é outro caso típico que pode ser resolvido através de um algoritmo recursivo. O factorial de n, também representado por n!, em que n é um inteiro não negativo é calculado pela expressão n! = n * (n - 1) * (n - 2) *... * 1 Por exemplo, o factorial de 5 é 5! = 5 * 4 * 3 * 2 * 1 = 120 A função recursiva para o cálculo do factorial pode ser escrita tendo em consideração que o factorial de 0 é 1 (0! = 1). É esta condição que determina o final das chamadas recursivas. A função pode ser escrita em linguagem PE conforme se representa no programa 6.4. inteiro factorial( n ) inteiro n; se n == 0 então retorna 1; senão retorna n * factorial( n - 1 ); Programa 6.4. Função Recursiva para Cálculo do Factorial de um Número. Os subprogramas recursivos são formas elegantes de resolver alguns problemas particulares, que apresentariam soluções não-recursivas pouco compreensíveis e muito extensas. Este tipo de subprogramas tem larga aplicação em programas que lidam com estruturas de dados complexas. No entanto, as funções e procedimentos recursivos devem ser utilizadas criteriosamente porque cada chamada ocupa um determinado espaço na memória do computador. Esse espaço destina-se a guardar, por exemplo, valores de variáveis que devem ser repostos quando o subprograma terminar a sua execução e o local do programa a partir do qual foi invocado o subprograma. É fácil, em subprogramas recursivos, haver muitas chamadas que rapidamente esgotam os recursos de memória disponíveis para esse efeito. Funções e procedimentos recursivos que possam implicar um número elevado de chamadas deverão ser evitados. Erros mais Comuns

12 A correcta compreensão do âmbito de uma variável envolvida num programa e a análise das situações que permitem a escolha da forma de passagem de parâmetros são fundamentais na elaboração de programas de computador. Estes aspectos tornam-se mais críticos à medida que a complexidade dos programas aumenta. Os programas complexos podem envolver um número elevado de variáveis e a utilização de diversos subprogramas, implicando maiores cuidados na definição do âmbito das diversas variáveis e nas formas de passagem de argumentos. Um erro frequente consiste na utilização de uma variável global como se fosse uma variável local. Embora normalmente o computador não acuse qualquer erro, gera-se uma situação que, em geral, leva a um mau funcionamento do programa. Estas situações são normalmente difíceis de detectar. Os erros que ocorrem pela troca da forma de passagem de argumentos também podem ser difíceis de detectar e têm como consequências a alteração de valores de variáveis que se pretendiam inalteráveis (troca da passagem por valor pela passagem por referência) ou a não alteração de conteúdos de variáveis que se pretendiam modificar (troca da passagem por referência pela passagem por valor). Construção de um Programa em PE Após a apresentação das instruções condicionais e cíclicas e da utilização de subprogramas, é possível definir um conjunto de regras para desenvolvimento de programas com a linguagem PE. Estas regras são em tudo idênticas às regras que normalmente se encontram nas linguagens de programação disponíveis para utilização na generalidade dos computadores. No programa, terá então de existir um corpo principal, definido através do procedimento programa(), incluída nos programas apresentados até agora. O programa poderá incluir outras funções ou procedimentos, definidos pelo programador e cuja execução é controlada por programa(). /* Função calcula_média */ real calcula_média( n1, n2, n3, n4 ) inteiro n1, n2, n3, n4; real m; m = (n1 + n2 + n3 + n4) / 4; retorna m; /* Procedimento escreve_média */ escreve_média( x ) real x; escreva( "A média é", x );

Funções e Procedimentos 13 /* Função principal */ programa() constante inteiro número_alunos = 25; inteiro nota1, nota2, nota3, nota4; inteiro aluno = 1; real média; enquanto aluno <= número_alunos faça leia(nota1, nota2, nota3, nota4); média = calcula_média(nota1, nota2, nota3, nota4); escreve_média( média ); aluno = aluno + 1; escreva("calculada a média de ", número_alunos, " alunos"); Programa 6.5. Exemplo da Estrutura de um Programa em PE. O programa 6.5 é uma versão do programa 5.5 na qual foram definidos dois subprogramas: a função calcula_média() e o procedimento escreve_média(), colocados antes do procedimento principal programa(). Este, terá de existir sempre em qualquer programa em PE, sendo o bloco que é executado em primeiro lugar. No caso de existirem subprogramas com parâmetros, estes terão de ser declarados como é o caso de n1, n2, n3 e n4 em calcula_média() e x em escreve_média(). No caso de funções, terá de ser sempre definido o tipo do valor de retorno. No programa 6.5 estão incluídas linhas com comentários que, como já foi referido no capítulo anterior, são linhas que têm o objectivo de tornar mais legível a listagem do programa, chamando a atenção para aspectos considerados importantes. Exercícios 6.1. Desenvolva um procedimento que aceite como argumentos três números inteiros e imprima o maior e o menor desses números. 6.2. Escreva um procedimento que imprima os quadrados dos números inteiros compreendidos entre dois valores que são passados como argumentos ao procedimento.

14 6.3. Escreva uma função que implemente o algoritmo apresentado no exercício 2.7. 6.4. O número de combinações de n objectos diferentes, seleccionando p objectos de cada vez e não considerando a ordem na qual os objectos são seleccionados, é dado pela expressão Desenvolva uma função capaz de proceder ao cálculo desta expressão, recorrendo à função factorial() apresentada no programa 6.4. 6.5. O cálculo de combinações pode também ser efectuado através da expressão Escreva uma função recursiva que efectue o cálculo de combinações utilizando a expressão apresentada. De notar que se n for igual a p ou p for 0 o resultado é igual a 1; se p for 1 o resultado é igual a n. 6.6. O fluxograma seguinte representa um algoritmo que permite efectuar a multiplicação de números naturais. Escreva a função em PE correspondente ao algoritmo representado. 6.6. Escreva a função digito( n, k ) que retorna o valor do dígito colocado na posição k, contada a partir da direita, de um número inteiro n. Se não existir nenhum dígito na posição indicada, a função retornará o valor 0. Por exemplo, digito( 98263, 4 ) - retorna 8 digito( 256, 8 ) - retorna 0 6.7. Escreva uma função que determine, numa sequência de valores lidos, terminada com o valor 0, o número de subsequências não decrescentes. Por exemplo, dada a sequência (2, 8, 6, 7, 8, 2, 1, 3, 5, 6), a função deverá encontrar as subsequências (2, 8), (6, 7, 8) e (1, 3, 5), retornando o valor 3. 6.8. Escreva um procedimento que implemente o algoritmo proposto no exercício 2.8. 6.9. A força de atracção entre dois corpos de massas m1 e m2, separados por uma distância r é dada pela expressão em que G = 6,673 x 10-11 N m 2 Kg -2

Funções e Procedimentos 15 Escreva uma função que dadas as massas de dois corpos e a distância que os separa, calcule a força de atracção entre eles. 6.10. Um jogo designado por Torres de Hanoi popularizou-se na Europa no final século passado. Este jogo consistia em três cilindros verticais nos quais encaixava um conjunto de 64 discos de tamanhos diferentes. De acordo com a figura (exemplo para 5 discos) o objectivo do jogo é o de transportar os discos do cilindro da esquerda para o cilindro da direita, com o auxílio do cilindro do meio. Os discos devem ser movidos um de cada vez e nunca deverá ficar um disco maior colocado sobre um disco menor. Escreva uma função recursiva que resolva este problema. Torres de Hanói: Exemplo com 5 Discos 6.11. Escreva uma função que converta letras minúsculas para letras maiúsculas. A letra minúscula será passada como argumento à função e a correspondente letra maiúscula será retornada. Deverá usar a função pré-definida ascii() e consultar a tabela apresentada no apêndice A. Resumo 1 A utilização de subprogramas num programa apresenta um conjunto de vantagens: a) Reduzir ou eliminar sequências de linhas de programação idênticas, relacionadas com uma única tarefa, incluindo essas linhas num subprograma que será executado sempre que o programa o exija. b) Aumentar a legibilidade dos programas escondendo pormenores pouco relevantes para a compreensão do problema. c) Reduzir o tamanho e a complexidade dos programas, dividindo-os num conjunto de subprogramas mais simples. d) Permitir a utilização de conjuntos de funções e procedimentos genéricos (bibliotecas) por outros programas, evitando a reescrita de subprogramas. 2 É possível distinguir dois tipos diferentes de subprogramas: as funções e os procedimentos. As funções distinguem-se dos procedimentos pelo facto de devolverem um valor ao programa que as invoca. Tanto as funções como os procedimentos podem, por sua vez, utilizar outras funções ou procedimentos.

16 3 As variáveis dentro de um programa podem apresentar âmbitos distintos: global ou local. Uma variável local é apenas reconhecida no bloco em que se encontra definida não podendo ser acedida a partir de outros blocos. Uma variável global é reconhecida em todo o programa podendo ser acedida a partir de qualquer parte do programa. 4 A passagem de argumentos a um procedimento pode ser feita por valor ou por referência. No primeiro caso são criadas no procedimento cópias dos argumentos que são destruídas quando o procedimento termina. No segundo caso, é indicado ao procedimento as posições de memória ocupadas pelos argumentos. Nesta última situação, as alterações efectuadas sobre os valores dos parâmetros do procedimento reflectem-se de igual forma nos valores dos argumentos. 5 Em muitas situações é conveniente usar funções ou procedimentos com capacidade de se invocarem a si próprios. Os subprogramas com estas características designam-se por subprogramas recursivos. 6 Um programa na linguagem PE terá de incluir o procedimento programa(). O programa inicia a sua execução a partir deste procedimento. Para além do procedimento programa() poderão existir outros subprogramas (funções ou procedimentos) definidos pelo programador. Estes deverão ser sempre colocados antes do procedimento programa().