MC102
Algoritmos e Programação de Computadores
Parte XVI



Norton Trevisan Roman




PASSAGEM DE PARÂMETROS POR VALOR E REFERÊNCIA

Até agora, tudo que podíamos fazer com procedimentos era passar valores a eles. Mas, e como retirar um valor deles?

Considere o seguinte exemplo: quero um procediemtno que, dadas 3 notas, tire sua média conforme a fórmula:

m = (2 × n1 + 3 × n2 + 5 × n3 ) ÷ 10

como faço? Até o que sabemos, podemos fazer:
  PROCEDURE media(n1,n2,n3 : real);
  VAR m : real;
  BEGIN
    m := (2*n1 + 3*n2 + 5*n3) / 10;
    write(m)
  END;
        

Mas, e se quisermos usar o valor de m depois? Podemos fazê-lo global:

  PROGRAM P;
  VAR m : real;

  PROCEDURE media(n1,n2,n3 : real);
  BEGIN
    m := (2*n1 + 3*n2 + 5*n3) / 10
  END;

  BEGIN
    media(3.5,8,10);
    write(m)
  END.
        

Funciona? Claro! MAs é horrível. Por que? Porque não é desejável que variáveis globais sejam modificadas dentro de procedimentos, pois, se tivermos dezenas de procedimentos em nosso programa, podemos nos confundir. Então o que faremos? Temos que ter um meio de calcular a média no procedimento e retirar o valor de lá. Como? Passando uma variável por referência:

   PROGRAM P;
1. VAR m : real;

4. PROCEDURE media(n1,n2,n3 : real; VAR resp : real);
   BEGIN
5.   resp := (2*n1 + 3*n2 + 5*n3) / 10
   END;

   BEGIN
2.   media(3.5,8,10,m);
3.   write(m)
   END.
        

Notou o VAR no parâmetro de "media"? Ele indica que a variável que segue a ele é passada por referência.

Como funciona um parâmetro por referência? Pense nele como uma variável local sem personalidade. Ela precisa de personalidade e, quando passamos a ela uma variável (como na linha 2. do programa acima), essa variável (no caso resp) assume a personalidade da variável passada (m). Ou seja, no nosso exemplo, tudo que fizermos com resp estaremos, na verdade, fazendo com m.

Vamos ver o diagrama de execução do programa:

1:

2:

5:

3:

Veja em 2 como representamos que resp recebeu m por referência: usamos uma seta indicando que qualquer mudança em resp será feita em m, o que de fato ocorre em 5, quando, ao darmos valor para resp, estamos dando para m.

Essa seta póde ser vista como resp apontando para seu chefe, m. Então quando queremos algo com resp e vamos a ela (para por exemplo, ler seu val.or ou guardar algo nela), resp diz: "Não é comigo, é com ela!" e aponta para m. Assim, ao lermos resp lemos m, e ao modificarmos resp, modificamos m.

Vamos ver um exemplo:

   PROGRAM A;
1. VAR x,y : real;
2.     a,b : integer;

3. PROCEDURE B(x : real; VAR y : integer);
4. VAR z : integer;
   BEGIN
5.   z := Trunc(x / 2);
6.   y := 2*z
   END;

   BEGIN
7.   x := 3.1416;
8.   B(x,a);
9.   write(a);
10.  y := 2*x;
11.  B(x+y,b);
12.  write(b)
   END.
        

1 e 2:

7:

8, 3 e 4:

5:

6:

Note que modifiquei o "a".

9:

10:

11, 3 e 4:

5:

6:

12:

Estude atentamente os quadros acima e note que:

Então, em suma: B(x) Observação: uma vez que posso ler de dentro do procedimento o valor que há na variável que foi passada por referência, posso fazer coisas do tipo:
   PROGRAM A;
   VAR x : integer;

     PROCEDURE B(VAR n : integer);
     BEGIN
       n := (n * 5) MOD 3
     END;

   BEGIN
     x := 4;
     B(x);
     write(x)  {x = 2}
   END.
        

Em B, pego o valor anterior de x, 4, multiplico por 5, pego o resto da multiplicação dividida por 3 e guardo em x.

Por fim, podemos chamar procedimentos de dentro de procedimentos, passando os parametros por referencia. Por exemplo:

1.   PROGRAM A;
2.   VAR x : integer;

3.     PROCEDURE B(VAR n : integer);
       BEGIN
4.       n := (n * 5) MOD 3
       END;

5.     PROCEDURE C(VAR m : integer);
       BEGIN
6.       B(m);
7.       m := m + 3
       END;

     BEGIN
8.     x := 4;
9.     C(x);
10.    write(x)  {x = 5}
     END.
        

Vamos fazer o diagrama de execuçao:

1 e 2 - o programa é definido:

8 - atualizo x:

9 e 5 - chamo C passando x por referência:

6 e 3 - chamo B passando m por referência. Note que, como m é uma encarnação de x, o que passo a B é x por referência:

4 - aqui é mais truculento. Primeiro devo pegar o valor de n e então fazer a conta e por em n novamente:


Então vamos pegar o valor de n. Primeiro o compilador busca em n, esse diz: "não é comigo, é com o m", aí o compilador vai buscar em m o valor que ele quer, e m diz: "não é comigo, é com x". Finalmente, o compilador busca o valor em x. É muito semelhante a uma repartição pública não?
Agora, após feito o cálculo, o compilador tenta colocar o resultado em n, esse diz que não é com ele, e sim com m. O compilador, então tenta por em m e esse diz que não é com ele, e sim com x, aí o compilador tenta, e consegue, por o valor em x.
Notou qual variável foi modificada no final das contas? x.

7 - modificamos m, modificando x:

10 - a saída é impressa:





‹— Parte XVPágina da disciplinaParte XVII —›