Instrucciones de salto
Las instrucciones de salto permiten modificar el flujo del programa,
forzando la siguiente iteración de un bucle antes de tiempo, o la salida del
mismo o bien enviando la ejecución a un punto determinado del programa.
La instrucción Break
La instrucción break fuerza la salida de un bucle antes de tiempo o bien de
una estructura de control de flujo condicional en la que se encuentre. Un
ejemplo sencillo:
class InstruccionBreak
{
static void Main()
{
int num=0;
while (true)
{
Console.WriteLine(num);
num+=5;
if (num>100) break;
}
string a=Console.ReadLine();
}
}
El bucle while (true) es un bucle infinito, sin embargo, cuando la variable
num tiene un valor mayor que 100 la ejecución del bucle terminará, pues se
ejecuta una instrucción break.
Instrucción Continue
La instrucción continue fuerza la siguiente iteración del bucle donde se
encuentre (que puede ser un bucle for, while, do o foreach). El siguiente
programa mostrará todos los números del uno al veinte a excepción de los
múltiplos de tres:
class InstruccionContinue
{
static void Main()
{
for (int i=1;
i<=20; i++)
{
if (i % 3 == 0) continue;
Console.WriteLine(i);
}
string a=Console.ReadLine();
}
}
El bucle for va asignando valores a la variable i entre 1 y 20. Sin
embargo, cuando el valor de i es tres o múltiplo de tres, se ejecuta una
instrucción continue, de modo que se fuerza una nueva iteración del bucle sin
que se haya escrito el valor de i en la consola. Por tanto, aparecerían todos
los números del uno al veinte a excepción de los múltiplos de tres.
Instrucción GOTO
Goto hace que la ejecución del programa salte hacia el punto que se le
indique.
Hay ocasiones en las que una instrucción goto hace la lectura de un programa
mucho más fácil y natural, pero hay que utilizarla con mucha precaución, pues
puna programación poco cuidadosa y poco planificada puede hacer que los
resultados con esta instrucción sean muy difíciles de seguir y evaluar.
En este ejemplo, si opción vale 2 se asigna una cadena a la variable regalo
y, además se le asigna 5 a la variable descuento. En este caso un goto
resulta más natural, intuitivo y fácil
de leer:
switch (opcion)
{
case 1:
descuento=10;
break;
case 2:
regalo="Cargador de DVD";
goto case 3;
case 3:
descuento=5;
break;
default:
descuento=0;
break;
}
Pero hay muchos casos en los utilizar goto es contraproducente, por
ejemplo:
if (opcion==1) goto Uno;
if (opcion==2) goto Dos;
if (opcion==3) goto Tres;
goto Otro;
Uno:
{
descuento=10;
goto Fin;
}
Dos:
{
regalo="Cargador de DVD";
}
Tres:
{
descuento=5;
goto Fin;
}
Otro:
descuento=0;
Fin:
Console.WriteLine("El descuento es {0} y el regalo
{1}",
descuento, regalo);
Este fragmento de código hace lo mismo que el anterior, pero, es más difícil
de leer, y no cumple los principios de la programación estructurada. Un mal uso
de goto puede hacer que un programa sencillo en principio se convierta en una
fuente de problemas.
El uso de goto debe realizarse sólo
en casos muy concretos en los que verdaderamente haga la lectura del código más
fácil (como en el ejemplo del switch), aunque, incluso en este caso se
podría haber suprimido.
Recursividad
Los métodos recursivos son métodos que se llaman a sí mismos. Esto puede
dar la impresión de que la ejecución no terminaría nunca, aunque los métodos
recursivos han de finalizar en algún punto. Utilizaremos un ejemplo para
calcular un factorial.
static double Fact(byte num)
{
if (num==0) return 1;
return num*Fact((byte) (num-1)); // Fact se llama a sí mismo
}
Se utiliza el tipo doublé, porque es el que admite valores más grandes, sí,
más que el tipo Decimal, ya que se almacena en memoria de un modo diferente.
Por otro lado, uso el tipo byte para el argumento porque no tendría sentido
usar un tipo que acepte números mayores, ya que pasando de 170 el valor del
factorial no cabe ni si quiera en el tipo double.
Cuando en el programa hace una llamada al método Fact este, comienza su
ejecución. Primero comprueba si el argumento que se le ha pasado es igual a
cero. Si por ejemplo el argumento vale 3, el método retornará lo que valga el
producto de 3 por el factorial de 3-1, o sea, 3 por el factorial de 2. Para
poder retornar esto debe calcular previamente cuánto vale el factorial de 2,
por lo se produce la segunda llamada al método Fact. En esta segunda llamada,
sucede algo parecido: el argumento vale 2, y como no es igual a cero el método
procede a retornar 2 por el factorial de 1 (2 - 1), pero, vuelve a suceder
igual. Para poder retornar esto ha de calcular previamente cuánto vale el
factorial de 1, por lo que se produce la tercera llamada al método Fact,
volviendo a darse de nuevo la misma situación: como 1 no es igual a cero,
procede a retornar el producto de 1 por el factorial de cero, y de nuevo tiene
que calcular cuánto vale el factorial de cero, por lo que se produce una nueva
llamada al método Fact. Sin embargo esta vez sí se cumple la condición, es
decir, cero es igual a cero, por lo que esta vez el método Fact retorna 1 al
método que lo llamó, que era el que tenía que calcular previamente cuánto valía
el factorial de 0 y multiplicarlo por 1. Así, la función que tenía que calcular
1*Fact(0) ya sabe que la última parte, es decir, Fact(0), vale 1, por lo que
hace el producto y retorna el resultado al método que lo llamó, que era el que
tenía que calcular cuánto valía 2 * Fact(1). Como este ya tiene el resultado de
Fact(1) (que es, 1*1), ejecuta el producto, retornando 2 al método que lo
llamó, que era el que tenía que calcular cuánto valía 3*Fact(2). Como ahora
este método ya sabe que Fact(2) vale 2, ejecuta el producto y retorna el
resultado, que es 6, finalizando el programa.
Un método recursivo va llamándose a sí mismo hasta que se cumple la
condición que hace que termine de llamarse, y empieza a retornar valores en el
orden inverso a como se fueron haciendo las llamadas.
No hay comentarios:
Publicar un comentario