Site icon Embarcados – Sua fonte de informações sobre Sistemas Embarcados

Funções e Procedimentos – Parte 2

PSEUDOCODIGO bubble sort switch case

Oi pessoal!!! Hoje darei continuidade à explicação de Funções e Procedimentos. No artigo passado vimos como criar uma Rotina sem parâmetros e sem retorno e, no artigo de hoje, estudaremos como fazer uma Rotina com passagem de parâmetros por valor sem retorno. Bora lá?

Rotina com passagem de parâmetros por valor sem retorno

Você pode criar rotinas com parâmetros e sem retorno, isso significa que elas receberão parâmetros vindos de quem a chamou, mas não retornarão um valor de um tipo especifico para quem está chamando. Vejamos a Listagem de Código abaixo:

Listagem 1: Programa para uma calculadora simples usando procedimentos e funções com parâmetros (passagem por valor) e sem retorno

A Listagem 1 é muito parecida com a Listagem do artigo passado. Na verdade, ela faz exatamente a mesma coisa, só que de forma diferente. Vamos entender essa listagem antes de falar sobre as chamadas e retornos. A Linha 1 define o nome do programa “program calculadora”. Na linha 4 são definidas as bibliotecas que serão utilizadas no programa “uses wincrt, crt;”, que são as bibliotecas básicas para trabalhar com entrada e saída no programa (leitura do teclado e escrita na tela).

A linha 7 define o escopo das variáveis globais, sendo declaradas na linha 8 as variáveis que serão utilizadas por todas as rotinas do programa que desejarem: “n1” para o primeiro operando, “n2” para o segundo operando e “opcao” para selecionar a opção desejada no menu de opções do programa.

Na linha 11 tem inicio a rotina para realizar a leitura dos operandos, isto é, para solicitar ao usuário dois números que serão utilizados nas rotinas posteriores. Observe que esta rotina não tem parâmetros e nem retorno, portanto, é um procedimento em pascal. Os dois operandos são lidos do teclado e seus valores armazenados em n1 e n2 respectivamente.

As linhas 20 a 23 correspondem à rotina para calcular a soma entre os dois operandos lidos, n1 e n2. Esta rotina exige dois parâmetros do tipo inteiro, também chamados de n1 e n2. Isso significa que quando você chamar essa rotina, você deverá passar pra ela dois valores do tipo inteiro, caso contrário, ocorrerá um erro. Essa rotina não tem retorno explicito, mas sim implícito, isto é, ela retornará para quem chamou, o texto “Soma: “, com o valor resultante da soma entre n1 e n2.

As rotinas para subtração (26-29), multiplicação (32-35), potência (51-55) e raíz (58-62) quadrada são exatamente iguais à rotina para soma. Para as rotinas que envolvem divisão (38-48), quociente (78-88) e resto (65-75), é preciso verificar se haverá divisão por zero. Defini que, para essas rotinas, n1 será dividido por n2, então, n2 não pode ser zero, se for, ocorrerá o erro de divisão por zero e o programa parará. Assim, fazemos um IF para tratar isto: se n2 for igual a zero, então emitimos uma mensagem para o usuário, dizendo que não existe divisão por zero; caso contrário, a divisão, ou resto, ou o quociente, é calculado normalmente.

As linhas de 92-161 compreendem à rotina para a composição do MENU de opções. O usuário deverá escolher uma entre as oito opções listadas. Usamos um switch/case para fornecer essa funcionalidade ao usuário. Primeiro listamos as opções, depois criamos os casos, chamando primeiro a leitura de operandos e depois a rotina desejada. Um writeln(”) ao final de cada caso é usado apenas para deixar a tela do console um pouco mais organizada e menos confusa. Observe que em todas as chamadas de rotinas são passados os parâmetros n1 e n2 que são lidos na rotina leitura().

Por fim, as linhas de 163-165 compreendem o programa principal, que consiste apenas de uma linha que é a chamada à rotina MENU. A partir dela, tudo acontece. Bem, agora que passamos um geral no código, vamos ver detalhes sobre as rotinas com parâmetros sem retorno. Observem a assinatura dos procedimentos:

procedure raiz(n1, n2  : integer);

Todos os procedimentos, menos o procedimento para o MENU e para a LEITURA, tem n1 e n2 em sua assinatura. Isso significa que a rotina precisa desses valores para trabalhar. Assim, quando vocês chamarem a rotina, deverão passar esses dois valores inteiros, que são parâmetros. Aqui esses valores são lidos na rotina LEITURA, que usa as variáveis declaradas globalmente, e então são passadas para a rotina desejada, são exatamente as mesmas variáveis. A chamada da rotina também muda, vejam:

raiz(n1,n2);

Agora passamos n1 e n2 na chamada da rotina e não mais como na Listagem do artigo anterior que era assim:

raiz();

O que volta para quem chamou? Volta o que está no corpo da rotina. No caso da raiz são dois writeln(), que imprimem na tela os valores da raiz dos dois números. É exatamente isso que veremos quando chamarmos a rotina. Observe as Figuras abaixo:

Figura 1: Testando a Opção 4 com n1 = 159 e n2 = 753.
Figura 2: Testando a Opção 4 com n1 = 5 e n2 = 10.
Figura 3: Testando a Opção 4 com n1 = 5 e n2 = 9.
Figura 4: Testando a Opção 4 com n1 = 2 e n2 = 0, resultando em uma divisão por zero que não é permitida.
Figura 5: Testando a Opção 4 com n1 = 0 e n2 = 5.
Figura 6: Testando a Opção 4 com n1 = 10 e n2 = 5.
Figura 7: Testando a Opção 5 com n1 = 20 e n2 = 30.
Figura 8: Testando a Opção 6 com n1 = 54 e n2 = 78.
Figura 9: Testando a Opção 7 com n1 = 60 e n2 = 0, resultando em uma divisão por zero que não é permitida.
Figura 10: Testando a Opção 7 com n1 = 0 e n2 = 60.
Figura 11: Testando a Opção 8 com n1 = 74 e n2 = 0, resultando em uma divisão por zero que não é permitida.
Figura 12: Testando a Opção 8 com n1 = 0 e n2 = 56.

As Figuras mostram a execução do programa, opção à opção, inclusive testando quando há divisão por zero. Assim, notamos que o código fonte utilizado aqui está funcionando corretamente. Então, vamos recapitular alguns conceitos importantes envolvidos em nosso exemplo.

Parâmetros: são as variáveis situadas na assinatura de um método ou função. Um parâmetro é um valor que vem de uma variável, ou de uma expressão, que é passado para uma rotina, a qual utiliza esses valores atribuídos aos parâmetros para alterar o seu comportamento em tempo de execução.

Argumentos: são os valores atribuídos aos parâmetros. Vocês perceberam que eu usei apenas a palavra Parâmetros nos artigos, isto porque não existe uma real diferença no seu uso.

Chamada de Rotina (procedimento ou função): é um mecanismo pelo qual uma parte do programa de computador solicita que uma tarefa seja realizada por outra parte dele próprio, no caso, uma rotina. Uma chamada de rotina ocasiona um desvio na execução do programa.

Passagem de Parâmetros: valores são passados para as rotinas.

Passagem de Parâmetros por Valor: é a forma mais comum de passar valores a uma rotina. Uma cópia da variável inteira é feita e esta pode ser usada e alterada dentro da função sem afetar a variável da qual ela foi gerada. Isso significa que o valor dos parâmetros sendo alterados durante a execução da rotina não acarretará em nenhuma modificação no valor dos parâmetros reais (variáveis da função chamadora).

Passagem de Parâmetros por Referência: o endereço da variável é transferido, isto significa que um ponteiro é manipulado na rotina. Esta forma deve ser usada quando uma rotina precisa ser capaz de alterar os valores das variáveis usadas como argumentos, os parâmetros então precisam ser explicitamente declarados como tipos ponteiros. No códigos fontes deste artigo, e do anterior, não usamos passagem de parâmetros por referência. Isso significa que qualquer alteração no valor dos parâmetros durante a execução da rotina será refletida no valor de seus parâmetros reais correspondentes. A parte de ponteiros será estudada na série de ESTRUTURAS DE DADOS.

Visualizando a passagem dos parâmetros

Vamos tentar entender como funciona a passagem de parâmetros. Como bem sabemos, e já foi explicado no artigo anterior, o programa principal chama a rotina MENU() e é assim que tudo começa. Dentro do MENU() temos o switch/case que permite ao usuário escolher uma opção.

Vamos então supor que nosso usuário escolheu a opção 2, a subtração, ele digitou o número 2 quando lhe foi solicitado escolher uma opção. O que ocorreu quando ele digitou o número 2? O case analisou a variável opção “Case opcao of”, que é 2, então, o programa vai para o Case 2. No corpo de Case 2 a primeira coisa a ser feia é chamar a rotina leitura(), então, Case 2 chama leitura(). A rotina leitura não retorna nada, pois é um procedimento sem parâmetros e sem retorno, mas ela realiza a leitura dos dois operandos n1 e n2 e devolve o controle para quem a chamou.

Após a chamada e retorno, é chamada agora a rotina subtrair(n1,n2), isso significa que os valores lidos em leitura serão passados para o n1 e n2 da rotina subtrair. Então se n1 é 5 e n2 é 10, estaremos passando subtrair(5,10). Então, a rotina procedure subtrair(n1, n2 : integer) receberá 5 para n1 e 10 para n2, o que nos permite pensar o seguinte procedure subtrair (5, 10 : integer). A rotina então fará a subtração de n1 com n2 e imprimirá na tela a saída desse resultado, retornando o controle da execução do programa para quem a chamou, Case 2. Por fim, o Case 2 imprime uma linha vazia no console: writeln(”). A Figura 13 mostra um fluxograma simplificado das chamadas e retornos das rotinas e a Tabela 1 mostra o teste de mesa simples.

Tabela 1: Teste de Mesa

opcaoleitura()subtracao(n1, n2 : integer)writeln(” Subtração: “, n1 – n2);
 n1n2  
2510

subtracao(5, 10 : integer)

writeln(” Subtração: “, 5 – 10);

Figura 13: Fluxograma de chamadas e retornos simples

Conclusão

Lembram-se do artigo anterior, em que apresentei a pilha de execução de chamadas e retornos de rotinas? Pois bem, deixarei esse tópico como exercício para vocês. Se tiverem dúvidas, deixem ali nos comentário que responderei com prazer, ok?! Até o próximo artigo pessoal.

Outros artigos da série

<< Funções e Procedimentos – Parte 1Funções e Procedimentos – Parte 3 >>