[ Foro de Pascal ]

Truco para que una función devuelva más de un valor

05-May-2013 13:40
Fulanito de Tal
5 Respuestas


 
program funcion_mas_de_un_valor_record;
 
uses
	crt, math;
 
type
	Tcuadrado = record
		superficie: real;
		perimetro: real;
	end;
 
var
	cuadrado: Tcuadrado;
	lado: real;
 
function calculos (lado: single): Tcuadrado;
	begin
	calculos.superficie := lado ** 2;
	calculos.perimetro := 4 * lado;
	end;
 
begin
clrscr;
 
writeln ('Superficie y perímetro de un cuadrado');
writeln ('-------------------------------------');
write ('Teclea el lado: ');
readln (lado);
 
cuadrado := calculos(lado);
 
writeln;
writeln ('Superficie: ', cuadrado.superficie:0:4);
writeln ('Perímetro: ', cuadrado.perimetro:0:4);
end.
 



05-May-2013 13:41
Fulanito de Tal

¡Hola!
Pues he metido la pata y no he puesto el mensaje completo anteriormente, así que lo pongo ahora completo y pido disculpas.

En Pascal una función no puede devolver más de un valor. Sin embargo hay un truco que nos permite hacerlo. Consiste en definir un tipo de dato como array o record, y hacer que la función devuelva al programa principal un resultado con ese tipo de datos.

Como ejemplo, un programa que calcula el perímetro y la superficie de un cuadrado, dado el lado. La función recibe el lado como dato y devuelve perímetro y superficie.

Podemos hacerlo de dos maneras: usando arrays o registros. Si usamos arrays el programador tiene que acordarse a qué dato corresponde cada elemento.

Primer caso: array.

 
program funcion_mas_de_un_valor_array;
 
uses
	crt, math;
 
type
	Tcuadrado = array [1..2] of single;
	//en el primer elemento del vector guardamos la superficie del cuadrado
	//en el segundo elemento guardamos el perímetro
 
var
	cuadrado: Tcuadrado;
	lado: real;
 
function calculos (lado: real): Tcuadrado;
	begin
	calculos[1] := lado ** 2; //superficie
	calculos[2] := 4 * lado; //perímetro
	end;
 
begin
clrscr;
 
writeln ('Superficie y perímetro de un cuadrado');
writeln ('-------------------------------------');
write ('Teclea el lado: ');
readln (lado);
 
cuadrado := calculos(lado);
 
writeln;
writeln ('Superficie: ', cuadrado[1]:0:4);
writeln ('Perímetro: ', cuadrado[2]:0:4);
end.
 



Segundo caso: registro.

 
program funcion_mas_de_un_valor_record;
 
uses
	crt, math;
 
type
	Tcuadrado = record
		superficie: real;
		perimetro: real;
	end;
 
var
	cuadrado: Tcuadrado;
	lado: real;
 
function calculos (lado: single): Tcuadrado;
	begin
	calculos.superficie := lado ** 2;
	calculos.perimetro := 4 * lado;
	end;
 
begin
clrscr;
 
writeln ('Superficie y perímetro de un cuadrado');
writeln ('-------------------------------------');
write ('Teclea el lado: ');
readln (lado);
 
cuadrado := calculos(lado);
 
writeln;
writeln ('Superficie: ', cuadrado.superficie:0:4);
writeln ('Perímetro: ', cuadrado.perimetro:0:4);
end.
 



11-May-2013 00:25
Nacho Cabanes (+31)

Efectivamente.

Aun así, te falta una tercera forma, que posiblemente es la más natural: pasar dos parámetros por referencia.

 
procedure calcularPerimetroYSuperficie
    (lado: real, var perimetro: real, var superf:real);
 



12-May-2013 20:40
Fulanito de Tal

Es verdad, pero en este caso ya sería un procedimiento en vez de una función. Gracias


13-May-2013 00:53
Antonio P.G.

Hola,

Y también podría ser una función que, aparte de devolver el valor 'final', modificase de forma 'colateral' valores por referencia, no?

Es decir, una mezcla de los dos... aunque no le veo mucha utilidad...

Saludos!


13-May-2013 13:21
Nacho Cabanes (+31)

Efectivamente, podría ser un procedimiento o incluso una función, aunque no es algo habitual.

Yo lo he usado alguna vez para cosas como comprobar el ratón: una función que devolvía "true" (un booleano) si se había pulsado el ratón, y entonces se podía saber la X y la Y de esa pulsación, mirando dos parámetros pasados por referencia.

En general, yo prefiero aislar cosas: me parece más legible, aunque sea un poco más largo, tener 3 funciones separadas: un IsButtonPressed para ver si se ha pulsado y un GetX y un GetY para comprobar la posición.






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)