Ir para o conteúdo

Procedimentos e Funções - Passagem por Parâmetro / Passagem por Referência

Tenho reparado ao longo dos anos que este é um ponto de confusão para os programadores iniciantes (e até para alguns experientes) e como perceber isto é algo absolutamente essencial num programador a sério (e para os outros também), lembrei-me de iniciar este documento. Vou aplicar isto a Pascal, mas a verdade é que o conceito é necessário em qualquer linguagem.

Para quem não sabe, nos procedimentos e funções permitem a passagem de parâmetros (valores ou variáveis), que serão inseridos no momento da chamada desse procedimento ou função, e serão transmitidos ao proprio código do procedimento ou função para por ele serem usados.

Passagem por Parâmetro

program parametro;
var
    lado1,lado2:integer;

function AreaRect(LadoMenor,LadoMaior:integer):integer;
begin
       AreaRect:=LadoMenor*LadoMaior;
end;

begin
      Lado1:=6;
      Lado2:=4;
      Writeln(AreaRect(6,4),'cm2');  
      Writeln(AreaRect(Lado1,Lado2),'cm2');  
end.

Resultado (o que aparece no ecrã):

24cm2
24cm2

Aqui, LadoMenor e LadoMaior são duas variáveis passadas por parâmetro. Isto significa que o compilador gera duas variáveis dentro da função AreaRect, com os nomes LadoMenor e LadoMaior, e que quando a função é chamada, preenche essas variáveis com os valores indicados entre parentesis aquando da chamada da função.

Neste caso, as variáveis podem ser usadas para qualquer fim dentro da função, e assumir qualquer valor do tipo indicado. No entanto, quando acaba a execução da função, qualquer valor que lá esteja é perdido.

Por exemplo:

program parametro;
var
    valor1,valor2:integer;

procedure DuplicaValores(v1,v2:integer);
begin
       writeln('2º - Dentro: ',v1,' / ',v2);
       v1:=v1*2;
       v2:=v2*2;
       writeln('3º - Dentro: ',v1,' / ',v2);
end;

begin
      valor1:=6;
      valor2:=4;
      writeln('1º - Fora: ',valor1,' / ',valor2);
      DuplicaValores(valor1,valor2);
      writeln('4º - Fora: ',valor1,' / ',valor2);
end.

Resultado:

1º - Fora: 6 / 4
2º - Dentro: 6 / 4
3º - Dentro: 12 / 8
4º - Fora: 6 / 4

Por aqui se pode ver que:

  1. Antes de executar o procedimento, os valores eram 6 e 4.
  2. Dentro do procedimento, mas antes de proceder à multiplicação, os valores eram 6 e 4 (que foram copiados de fora para dentro do procedimento)
  3. Dentro do procedimento, já depois de efectuar a multiplicação, os valores passaram a ser 12 e 8, ou seja, as variaveis v1 e v2 assumiram correctamente os valores que lhes foram atribuidos.
  4. Uma vez fora do procedimento, as variaveis valor1 e valor2 continuam a mostrar os valores 6 e 4, ou seja, não refletem as alterações feitas dentro do procedimento.

Portanto, isto mostra que a passagem por parâmetro é útil para enviar valores para dentro do procedimento, mas inútil para os trazer de dentro do procedimento para o local de chamada.

É aqui que entra a passagem por referencia.

Passagem por Referência

A passagem por referência não cria duas variáveis com valores iguais aos que foram passados entre parentesis. O que ela faz é criar um atalho, dentro do procedimento ou função, para as variáveis originais. Deste modo, qualquer alteração feita dentro do procedimento é reflectida mesmo depois do procedimento ter terminado.

Para exemplo, fica o programa anterior, com apenas uma pequena alteração:

program parametro;
var
    valor1,valor2:integer;

procedure DuplicaValores(var v1,v2:integer);
begin
       writeln('2º - Dentro: ',v1,' / ',v2);
       v1:=v1*2;
       v2:=v2*2;
       writeln('3º - Dentro: ',v1,' / ',v2);
end;

begin
      valor1:=6;
      valor2:=4;
      writeln('1º - Fora: ',valor1,' / ',valor2);
      DuplicaValores(valor1,valor2);
      writeln('4º - Fora: ',valor1,' / ',valor2);
end.

Resultado:

1º - Fora: 6 / 4
2º - Dentro: 6 / 4
3º - Dentro: 12 / 8
4º - Fora: 12 / 8

Apenas colocando a palavra reservada VAR antes dos parâmetros do procedimento, indicamos ao compilador que as variáveis que se seguem são apenas atalhos para outras, e que deveram ter sempre o mesmo valor, tanto dentro como fora do procedimento ou função. Assim, o resultado final (4º) já depois de terminado o procedimento, manteve o valor multiplicado que se efectuou dentro do procedimento.

Isto obriga, no entanto, a que os valores que colocamos entre parentesis sejam variáveis.

Se com o procedimento indicado em cima usássemos...

DuplicaValores(6,4);

...o compilador iria dar erro, pois está à espera de variáveis que possam receber valores. Números absolutos e constantes não são permitidas por este motivo.

Do mesmo modo, usar na chamada uma variável, mas que não seja do mesmo tipo do declarado dentro do procedimento ou função, também iria ser gerado um erro:

program erro;
var
   x:real;

procedure teste(var y:integer);
begin
     writeln(y);
end;

begin
    x:=5.15;
    teste(x);
end.

Este código não iria funcionar. Daria um erro ao compilar, pois os tipos de variáveis são diferentes.

Passagem por Parâmetro Constante

Existe uma terceira hipotese, embora seja na verdade apenas uma variante da passagem por parâmetros. A única diferença é que em vez do compilador criar variáveis dentro do procedimento ou função, cria constantes, o que significa que mesmo dentro do procedimento ou função os seus valores não podem ser alterados.

Conclusão

Espero que com isto seja mais fácil perceber a diferença e especialmente a importância destes conceitos para um programador.