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.

