Jump to content

Passagem por Parâmetro / Passagem por Referência


nunopicado

Recommended Posts

Ora então boa noite...

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 tópico.

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 procedimentou 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 paravra chave 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.

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

Se alguma duvida persistir, é só dizerem!

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Muito bom....

Lembro-me bem da dificuldade de entender este conceito quando andei a aprender pascal.

Apenas deixar um pequeno promenor, uma dificuldade que me aconteceu quando estava a aprender este conceito. Agora parece-me bastante obvio, mas na altura....

Quando temos uma função ou procedimento com variaveis passadas por referencia, isto é, as que se podem modificar dentro das próprias, têm de ser chamadas com variaveis e não com valores fixos.

Exemplo:

Procedure fazqqcoisa(var x:integer);
begin
  x:=x+1;
end;

.....

fazqqcoisa(5);      {chamada inválida}

fazqqcoisa(ab);      {chamada válida se a variavel ab for tipo integer}

Como disse agora parece-me bastante obvio.

Link to comment
Share on other sites

fazqqcoisa(5);      {chamada inválida}

hehehe

Isso está lá, mas obrigado pelo reforço, é isso mesmo! 👍

fazqqcoisa(ab);      {chamada válida se a variavel ab for tipo integer}

Pois, isto não disse... A variável passada por referência deve obrigatoriamente ser do mesmo tipo da que está declarada no procedimento ou função!

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Não tenho podido vir aqui nos últimos dias, mas amei este pequeno tutorial de Passagem por Parâmetro e por Referência. Os meus parabéns. Como sempre, explicas de forma excepcional, de tirar o chapéu. 😄

Assim que puder passarei para a Wiki. Se não te importares, vou fazer o link do Tutorial, quando falo de Procedimentos e Funções, para o teu documento. 😉

Faz falta estas pequenas coisas mas tão importantes! 😁

Knowledge is free!

Link to comment
Share on other sites

Está à vontade Thoga...

Usa como entenderes!

(e obrigado pelas palavras...)

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

nunopicado,

Uma boa explicação para algo que muita gente deixa passar sem querer saber 🙂

Queria apenas focar um aspecto que talvez não tenha ocorrido aos leitores. Quando estamos a trabalhar com funções/procedimentos cujos parâmetros contêm uma grande quantidade de informação, é sempre boa ideia utilizar abordagens pass-by-reference uma vez que a outra opção (pass-by-value) implica literalmente que seja criada uma cópia do parâmetro a ser passado.

De resto, gostei de ler. Queria que agora alguém desse o salto e começasse a falar de pointers em Pascal, visto que eu não consegui ainda arranjar o tempo para escrever algo sobre o assunto.

Link to comment
Share on other sites

É verdade Pedro, a passagem por referência acaba por consumir menos recursos por não haver cópia de valores.

Quanto aos ponteiros, vou deixar essa para ti! 🙂 Há anos que não lhes mexo, e mesmo na altura nunca dei grande uso, pelo que é melhor deixar a explicação para alguém que esteja mais à vontade com eles!

Abraço e obrigado

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

Os ponteiros é algo de de maravilhoso para quem necessita de velocidade no tratamento de registos.

Apenas para dar um exemplo, tinha programas de clientes e fornecedores, assentes em base de dados de registos de Pascal (vulgos records). Estes programas tinha diversas listagens. As mais morosas eram as que eram ordenadas por um campo qualquer... ou nome, ou código postal, ou mesmo dois campos em simultâneo tipo data e nome. Enfim, quem penso que estão a ver o objectivo.

Ora estas listagens ordenadas demoravam na ordem das 2 a 3 horas tanto que eu aconselhava às pessoas a executá-las à hora de almoço. Após a alteração dos programas e reprogramação com ponteiros as listagens passaram a demorar 2 a 3 minutos. E não, não estão a exagerar!!! :smoke:

Quem trabalha com file records, deve de apreender o conceito com mais facilidade, mas não é facil! :fartnew2:

Link to comment
Share on other sites

A questão dos pointers é que eles são essenciais para qualquer tipo de estrutura de dados que não seja uma array de um tipo de dados simples.

Uma vez que a base de qualquer programa eficiente assenta na escolha e implementação correcta de algoritmos que operem sobre estruturas de dados eficientes, e sabendo que os pointers são invariavelmente utilizados em tais estruturas de dados, é absolutamente essencial a sua compreensão e utilização para o desenvolvimento de programas com futuro.

Em C, as pessoas aprendem a usá-los porque sem eles de facto não fazem nada. Mas em Pascal há muita resistência ao conceito porque a linguagem facilita a sua não-utilização (e é necessário contrariar esta tendência), o que é absurdo, visto que a própria sintaxe para pointers é muito mais confortável que aquela vista em C.

Link to comment
Share on other sites

@pedro,

Fico à espera de umas palavrinhas tuas sobre pointers, uma vez que eu não sei nada sobre eles e as tentativas que já fiz para entrar nessa área foram infrutíferas.

Aliás, é o grande "buraco" do meu Tutorial, diga-se. 🙂

Precisamos de informação de confiança, mas leve e concisa. Estou farto de explicações extra-longas de nada. Força nisso quando tiveres tempo! 😛

Knowledge is free!

Link to comment
Share on other sites

  • 1 month later...

grande explicaçao, a pessoas assim a que se lhe dar o seus valor Os meus sinceros Parabens 😉

B) Obrigado...  😛

"A humanidade está a perder os seus génios... Aristóteles morreu, Newton já lá está, Einstein finou-se, e eu hoje não me estou a sentir bem!"

> Não esclareço dúvidas por PM: Indica a tua dúvida no quadro correcto do forum.

Link to comment
Share on other sites

  • 1 year later...

Puxa vida. Eu não sabia disso. Muito obrigado nunopicado. Não sabia que o uso da palavra chave var no escopo criava este tipo de efeito. Genial. Isso substitui ponteiros. :-)

Na realidade, é o que se pode chamar de syntactic sugar que o Pascal te oferece para evitares criar ponteiros para este fim de forma explícita. Eles são utilizados à mesma, nós é que não o "vemos" directamente no código. Torna-se mais agradável utilizar a keyword var. 🙂

Knowledge is free!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.