Curso básico de programación en Visual Basic

  Lección 6

Los bucles a fondo

 

Realizamos programas para la gestión de empresas. Empresas medianas y pequeñas. Programas de contabilidad, cartera de pedidos clientes proveedores, facturación control de albaranes, tesorería cartera de cobros y pagos y estadísticas.

Nuestro agradecimiento a todos los que por unas causas o por otras visitan nuestra web. Gestión de empresas PYMES. Curso de programación de Visual Basic.


 

Solución de los ejercicios de la Quinta Entrega
Pulsa este link para ver la solución de los ejercicios de la quinta entrega

Como hemos visto en el apéndice de la entrega anterior, la instrucción IF... THEN... nos permite tomar decisiones según el valor de una variable o el resultado de una expresión. En esta entrega veremos como sacarle rendimiento a esta instrucción.
Pero antes de entrar en detalles, veamos cómo podemos decirle al Basic que haga las cosas. En realidad vamos a ver la forma en que se le puede decir que las haga...

Forma de especificar las instrucciones en Visual Basic
Las instrucciones en Basic no tienen porqué estar cada una en una línea. Se pueden escribir varias instrucciones en la misma línea, pero separando cada una de ellas con el signo
: (dos puntos).
Cuando VB encuentra los dos puntos, deja de 'interpretar' la instrucción y pasa a la acción, una vez traducido a su lenguaje interno, toma lo que hay después del signo
: y sigue su camino en busca de más instrucciones o el final de la línea.

Veámoslo de forma práctica:
Nombre = "Pepe" : Print Nombre
Esta línea tiene dos instrucciones: una asignación y una instrucción Print.

Podemos poner cuantas instrucciones queramos, separadas con los dos puntos.

Pero, (siempre hay un pero), si una de las instrucciones es el IF/THEN la cosa puede cambiar...

Ya vimos que IF comprueba la expresión que viene a continuación, si es cierta, ENTONCES procesa lo que haya después de THEN. En caso de ser en la misma línea, interpretará todas las instrucciones que estén a continuación; en caso de ser un bloque IF... THEN... END IF, ejecutará todo lo que esté dentro de ese bloque. Ahora bien, si la expresión es falsa pasa a la siguiente línea, tanto si es o no un bloque. En el caso del bloque la siguiente línea a interpretar será la que esté después de END IF.

En los tiempos del BASIC interpretado de MS-DOS, era habitual encontrar las líneas con varias instrucciones separadas por dos puntos.
En mi caso, cuando empecé a usar el QuickBasic 2.0 y al poder usar bloques IF... THEN... END IF, fui dejando a un lado el "mogollón" de instrucciones en la misma línea...
Ahora, salvo en contadas excepciones, escribo cada instrucción en una línea. Y te recomiendo que hagas lo mismo, tu código ganará en claridad y si alguna vez vuelves a verlo, te será más fácil de entender.

Después de este pequeño respiro, veamos cómo estaría formada una línea de VB para usar con un IF... THEN...

[instrucciones:] IF <expresión> THEN <instrucciones si es cierto [:más instrucciones...]>

A continuación de THEN podemos incluir cuantas instrucciones queramos, separadas por dos puntos.
Estas sólo se ejecutarán cuando la expresión sea cierta. Si el resultado de la expresión es falso, se obvia 'todo' lo que hay después de THEN y se pasa a la siguiente línea.
Espero que lo hayas asimilado y que no te indigestes con lo siguiente...

Pero, (...), existe otra instrucción que PUEDE acompañar al IF... THEN... y es para los casos en los cuales el resultado de la expresión sea FALSO.
Si, ya sé que dije que cuando es falso se pasa a la siguiente línea, pero eso es cuando no se usa la cláusula ELSE.
Con ésta, la definición de la instrucción "tomadora de decisiones" quedaría así:

IF <expresión> THEN <si se cumple> ELSE <si no se cumple>

Tanto en <si se cumple> como en <si no se cumple> pondremos tantas instrucciones como queramos, (separadas por dos puntos).

Pero no te recomiendo que lo hagas, es preferible, al menos para darle "claridad" a nuestro código, usar el bloque:

IF <expresión> THEN
    <si se cumple>
ELSE
    <si no se cumple>
END IF

Sé que esto puede ocupar más líneas de código, pero nuestro "coco" lo agradecerá, ya que es más fácil de comprender, sino veamos un ejemplo:

IF numero > limite THEN
    Print "tu número es grande"
ELSE
    Print "OK, McKey!"
END IF

Ahora veámoslo en una sóla línea:

IF numero > limite THEN Print "tu número es grande" ELSE Print "OK, McKey!"

En este ejemplo, aún queda claro, pero lo podríamos complicar con más instrucciones para ambos casos, es decir, para cuando la expresión es cierta y también cuando es falsa.

En los tiempos del BASIC que venían incorporados con los ordenadores, cada línea del programa había que numerarla, ya que todo lo que se escribía sin número de línea, se ejecutaba inmediatamente; al igual que ocurre con lo que se escribe en la ventana Inmediate del Visual Basic.
Los números de líneas se usaban, además de porque era obligatorio, para cambiar el orden de ejecución, sobre todo después de una comparación. De esta forma, aún sin tener bloques IF/THEN/ELSE/END IF, se podían simular.
¿Cómo se lograba?
Usando una instrucción que muchos creen que es "indecente, antisocial, etc."
La estrella del Basic: (redoble de tambores) "GOTO"
A partir de hoy, más de un purista de la programación no me dirigirá la palabra... pero no me importa...

Se ha "denostado" (injuriado) con exageración el uso de esta instrucción.
Realmente es una instrucción de "bifurcación", es decir, sirve para "IR A" otro sitio de nuestro programa.
Su uso ha sido el más criticado de los NO PARTIDARIOS del Basic y siempre han basado sus críticas en el exagerado uso del GOTO en todos los programas Basic. Pero aclaremos que C también tiene esta instrucción y que cualquier programa en código máquina (ensamblador) está "plagado" de JMP que para el caso es lo mismo que el sufrido GOTO, realmente una instrucción GOTO número_linea se convierte en JMP número_linea.

No voy a recomendar el uso del GOTO, para nada, ya que hoy día es innecesario su uso. Antes no teníamos más remedio, porque el BASIC no disponía de instrucciones para poder estructurar el código. Pero sería una tontería querer hacer creer que no existe esta instrucción. Sabiendo que está y cómo podemos evitarla, es preferible a decir que no existe y si por casualidad la descubres... a que la uses.
Por tanto, insisto en mi recomendación, (de esta forma los PURISTAS volverán a dirigirme la palabra), NO USES EL GOTO, ni aún cuando creas que no tienes más remedio... aunque, aquí entre nosotros, algunas veces es más cómodo usarlo... pero que no se entere nadie...

Este es un programa de los de antes, sirve para mostrar en pantalla los números del 1 al 10 y sin usar el FOR/NEXT

10 A = 1
20 Print A
30 A = A + 1
40 IF A <= 10 THEN GOTO 20
'Con el Commodore este programa se solía escribir así:
10 A=1
20 PRINTA:A=A+1:IFA<=10GOTO20
'Sin ESPACIOS NI NADA... TODO APELMAZADO... ¿que más daba usar el GOTO?

Imagine there's no heaven... (es que está sonando J. Lennon... un momento...)

En este ejemplo, es obvio que podríamos sustituirlo con:

10 For A = 1 To 10
20     Print A
30 Next

El NEXT hace lo mismo que la asignación y la comparación.
Pero hay otras maneras, para ello existe una serie de instrucciones que funcionan de manera similar, veamos otros ejemplos con más instrucciones para hacer bucles, seguiré usando los números de línea por aquello de la "nostalgia", pero salvo en el primer ejemplo, en los demás no es necesario.

10 A = 1
20 While A <= 10
30    Print A
40    A = A + 1
50 Wend

El WHILE/WEND ya casi ni se usa, porque tienen un sustituto más versátil, ahora lo veremos, pero el uso sería:

WHILE <expresión>
    <instrucciones si se cumple>
WEND

Es decir, MIENTRAS la expresión sea cierta, repite todo lo que haya hasta el WEND.
Por supuesto podemos ponerlo todo en una sola línea:
10 A = 1 : While A <= 10 : Print A : A = A + 1 : Wend

Pero esto tampoco es recomendable, queda algo "difuso"...
El WEND funciona como IF A <=10 THEN GOTO xxx, con la ventaja que evitamos el GOTO y lo que hace es comprobar si la expresión que hay tras el WHILE es cierta o no, en caso de que sea verdadero el resultado, (ya sabes, distinto de CERO), se ejecutará todo lo que hay entre WHILE y WEND. Estas instrucciones ya existían en el GWBASIC (el basic de los PCs)

Hay que tener cuidado con esto de que la expresiones evalúan el cero como FALSO y cualquier otro valor como VERDADERO, por ejemplo:

A = 1			o
While A				While 1
    Print A			    Print A
    A = A + 1			    A = A + 1
Wend				Wend

En ambos casos el bucle sería "infinito", realmente se detendría en un momento dado, ya que llegaría a "desbordarse" el valor máximo y en ese momento el programa acabaría por producirse un error... pero prueba esto y verás:

While 1
    Print "Hola Mundo"
Wend

Esto nunca finalizará, salvo que pulses CRTL+BEAK (o INTERrumpir), para detener el programa.

 

Más instrucciones para hacer bucles

Con el QuickBasic 3.0, (yo no llegué a tenerlo, pero creo que fue ahí dónde se introdujo), entró en funcionamiento una nueva forma de hacer bucles:
DO... LOOP
El último ejemplo podríamos escribirlo así:

Do
    Print "Hola Mundo"
Loop

Pero la "gracia" de este tipo de bucle es que podemos usar dos nuevas cláusulas para evaluar cuanto durará el bucle.
La primera es WHILE y funciona igual que en WHILE/WEND

A = 1
Do While A <= 10
   Print A
   A = A + 1
Loop

La ventaja es que WHILE se puede poner tanto después de DO como a continuación de LOOP.
Si lo usamos como DO WHILE <expresión>... la forma de actuar es igual que WHILE/WEND, es decir, se evalúa la expresión y sólo en caso de que sea cierta, se ejecuta lo que está dentro del bucle, es decir entre DO y LOOP.
Pero si evaluamos la expresión en LOOP, se ejecutará todo lo que hay tras el DO, como mínimo una vez y se seguirá repitiendo si se cumple la condición. De esta forma, como he dicho, se ejecutará el contenido del bucle, como mínimo una vez.
Veamos un ejemplo:

A = 1
Do
   Print A
   A = A + 1
Loop While A <= 10

El problema es que si A, en lugar de valer 1, tiene un valor superior a 10, también se ejecutará, al menos, una vez.
A = 11 : Do : Print A: A = A + 1: Loop While A <= 10
Que mal queda en una sola línea, ¿verdad?

Pero con DO/LOOP también puede usarse UNTIL, en este caso, el bucle se repetirá HASTA que se cumpla la expresión

A = 1
Do Until A > 10
   Print A
   A = A + 1
Loop

Fíjate que la expresión ha cambiado de <= (menor o igual) a > (mayor), ya que ahora se evalúa de esta forma:
Hasta que A sea mayor que diez, REPITE todo hasta LOOP.
Por supuesto también podemos usarlo después del LOOP:

A = 1
Do
   Print A
   A = A + 1
Loop Until A > 10

Aquí hago la misma aclaración que antes, si el valor inicial de A es más de 10 se ejecutará como mínimo una vez.
Realmente para contar de forma secuencial y prácticamente para casi todo tipo de bucle, no es necesario hacer los bucles con DO/LOOP, ya que FOR/MEXT lo hace bastante bien.

Sigamos con estos bucles, pero en lugar de contar de menor a mayor, vamos a contar "pa trás", es decir de mayor a menor... quién sabe, lo mismo necesitas hacer un programa que cuente al revés...

A = 10
Do While A >= 1
   Print A
   A = A - 1
Loop

Cuando se muestre el 1, A=A-1 se convertirá en A = 0 y la comparación A >= 1 no se cumplirá, por tanto dejará de repetirse el bucle, pero esto también se puede hacer con FOR/NEXT:

For A = 10 To 1
    Print A
Next

El único inconveniente es que NO SE REPITE NI UNA VEZ... ¿Por qué?
Porque si no se le indica lo contrario, FOR/NEXT siempre cuenta de forma ascendente y cuando ve que A debe ir de 10 hasta 1 y que eso no es ascendente... pasa de ejecutar el bucle. Esto es una cosa a tener en cuenta, FOR siempre evalúa los valores del bucle que tiene que hacer y si no está entre los valores que debe, no se ejecuta ni una sola vez. En este caso debe empezar por DIEZ y llegar hasta UNO, así que se da cuenta de que ya ha terminado... incluso sin haber empezado... ¡que listo es el FOR!

Para que el FOR cuente hacia atrás, necesitamos un nuevo peldaño (esto en inglés quedaría "clavado"), en la escala evolutiva del FOR/NEXT (ahí queda eso!!!)
Ya sin coñas, se necesita la palabra STEP para indicarle que no queremos ir de uno en uno de forma ascendente, en nuestro ejemplo lo usaríamos así:

For A = 10 To 1 Step -1
    Print A
Next

De esta forma contará desde 10 hasta 1, restando uno en cada repetición.
Pero, ¿que hacer si queremos usar otros valores?
Simplemente ponerlo después de STEP, por ejemplo:
For A = 10 To 1 Step -1
For A = 1 To 10 Step 3, etc, etc.

Insisto, todo esto está muy bien, pero en la práctica usaremos otras cosas además de contar de forma lineal, con incrementos o sin ellos... habrá veces que queramos salir de un bucle.
Ya lo hemos visto, por ejemplo Exit Sub salía del procedimiento, ¿recuerdas el Exit For?
Para salir de los bucles podremos Exit y a continuación For, Do, etc. Pero NO podremos salir de un bucle WHILE/WEND.
Ya veremos ejemplos para estos casos y otros que surgirán más adelante.

Bien, creo que ya hemos dado demasiadas vueltas con tanto bucle, para terminar: los ejercicios esos que tanto os gustan.

1.) Haz un programa que al pulsar en un botón (CommandButton) haga un bucle entre dos valores que habrás introducido por medio de dos cajas de textos (una para el inicio y otra para el final)

2.) Otro que tenga una tercera caja de textos y que el valor introducido en ella sea el incremento.

3.) Como tercer ejercicio, una vez terminado el bucle, que muestre en un Label las veces que se ha repetido.
Por ejemplo, si hacemos un bucle del uno al diez de uno en uno, se repetirá diez veces; pero si lo hacemos de dos en dos, se repetirá cinco veces...
Como pista, decirte que no tendrás que hacer ninguna comparación para obtener el resultado, la solución es tan SIMPLE que seguramente la descartarás "porque no puede ser tan fácil"

Por supuesto, me gustaría que los bucles los hicieras tanto con FOR/NEXT y DO/LOOP. Ya puestos, podrías hacerlo con el WHILE/WEND e incluso con el GOTO...

¡Feliz programación!

Nos vemos.