ESTRUCTURAS CONDICIONALES IF

·          Introducción a los bloques de control

·         Alternativa simple. Instrucción IF

·         Sangría

·         Anidación

·         Instrucción IF simplificada

·         Alternativa doble. Instrucción IF-THEN-ELSE

·         Alternativa múltiple. Instrucción ELSEIF


INTRODUCCIÓN A LOS BLOQUES DE CONTROL

Hasta ahora al ejecutar nuestros programas se han ejecutado todas las instrucciones que aparecen en el listado del código fuente del programa, desde la primera hasta la última.

A partir de ahora vamos a poder conseguir que una o varias instrucciones solo se lleguen a ejecutar si se cumple una condición, que si no se cumple se ejecuten otras, o incluso que algunas instrucciones se ejecuten más de una vez (Esto lo veremos en los siguientes temas).

ALTERNATIVA SIMPLE. INSTRUCCIÓN IF

Empecemos con un ejemplo. Un programa que nos pida la nota de un examen y nos felicite si está aprobado.

CLS
INPUT "Escribe la nota del examen: ", nota
IF nota >= 14 THEN
               PRINT "Enhorabuena, has aprobado."
END IF
PRINT "Gracias por usar el programa."
Ahora ejecutemos el programa. Hemos sacado un 14:
Escribe la nota del examen: 14
Enhorabuena, has aprobado.
Gracias por usar el programa.

 

Volvamos a lanzar el programa, esta vez hemos sacado un 4:
Escribe la nota del examen: 4
Gracias por usar el programa.

Esta última vez se ha saltado una de las instrucciones del listado ¿Por qué?

Porque hemos usado la instrucción IF (si en inglés), una de las más importantes de todo lenguaje de programación estructurado, y le hemos puesto como condición que el valor almacenado en la variable nota sea mayor o igual que cinco con lo que hacemos que todas las instrucciones que haya entre IF y END IF solo se ejecuten si esta expresión es VERDADERA.

Vamos a ver con más tranquilidad la sintaxis de la instrucción IF

IF condición THEN
               instrucciones
END IF

SI la condición es VERDADERA, ENTONCES (THEN) se ejecutarán las instrucciones hasta llegar a END IF (FIN SI). Después se seguirá con el resto del programa

Si la condición es falsa se saltará todo el bloque IF y se ejecutarán las siguientes instrucciones del programa que haya después del END IF.



SANGRÍA

En el ejemplo anterior puedes ver que las instrucciones que hay dentro del bloque IF están escritas un poco más a la derecha que las demás, no justo en el margen izquierdo.

Esto se hace por comodidad, para poder saber de un vistazo cuales son las instrucciones que hay dentro del bloque. En la mayoría de lenguajes no es obligatorio (En COBOL sí), pero siempre es muy recomendable hacerlo así para dar mayor claridad al código fuente del programa.

Para hacer esto basta con pulsar la tecla TABULADOR antes de escribir la instrucción, mejor que escribir espacios. En las opciones de QBasic se puede especificar el tamaño de la tabulación (Cuantos espacios se escriben). Por defecto tiene 8, pero es mejor un número más bajo entre 3 y 5 como ya veremos más adenante.

Esta técnica también se conoce como encolumnado o indentación (En inglés se llama indent).


ANIDACIÓN

Como hemos visto en la sintaxis de la instrucción IF, dentro del bloque de instrucciones a ejecutar se puede usar cualquier instrucción, por lo tanto también se pueden usar otras instrucciones IF. A esto es a lo que se llama anidación de instrucciones. Veamos un ejemplo que nos diga si un número es par (usando el operador MOD) y en este caso nos diga también si el número es mayor que 10:

CLS
INPUT "Escribe un número: ", num
IF num MOD 2 = 0 THEN
               PRINT "Es un número par"
               IF num > 10 THEN
                               PRINT "Es mayor que 10"
               END IF
END IF

Ejemplos de la ejecución de este programa pueden ser...

Escribe un número: 7
Escribe un número: 8
Es un número par
 
Escribe un número: 12
Es un número par
Es mayor que 10

Aquí si la primera condición se cumple se escribe "Es par" y además se hace otra comprobación que se podrá cumplir o no. Nunca se va a llegar a la segunda comprobación si la primera no se ha cumplido.

Es muy importante observar que cada IF lleva su END IF correspondiente y que el bloque de instrucciones del segundo IF está encolumnado todavía más a la derecha que el anterior.

Cuando escribimos un programa en papel es común unir con una línea cada IF con su END IF para aclarar el listado.



INSTRUCCIÓN IF SIMPLIFICADA

Si el bloque de instrucciones de una instrucción IF sólo va a llevar una instrucción podemos escribirla en la misma línea detrás del THEN y ahorrarnos el END IF.

Para el ejemplo del examen podíamos haber hecho:

CLS
INPUT "Escribe la nota del examen: ", nota
IF nota >= 5 THEN PRINT "Enhorabuena, has aprobado."
PRINT "Gracias por usar el programa."

Esto es útil en algunos casos, pero si vemos que nos vamos a liar es mejor poner el END IF como hemos visto antes, aunque si nos acostumbramos a poner siempre los encolumnados no hay por qué equivocarse.

ALTERNATIVA DOBLE.
INSTRUCCIÓN IF-THEN-ELSE

En el ejemplo del examen estaría bien que "si no" aprueba, decirle que ha suspendido. Lo podemos hacer de esta forma:

CLS
INPUT "Escribe la nota del examen: ", nota
IF nota >= 5 THEN
               PRINT "Enhorabuena, has aprobado."
ELSE
               PRINT "Lo siento, has suspendido."
END IF
PRINT "Gracias por usar el programa."

En este caso se comprueba la condición del IF. Si es verdadera se ejecuta su bloque de instrucciones y después se sigue con lo que venga detrás del END IF, igual que antes. Ahora viene lo nuevo, si la condición no se cumple se ejecuta el bloque de instrucciones del ELSE hasta el END IF, y después se sigue con lo que haya detrás.

De esta forma nos aseguramos de que siempre se ejecuta uno y solo uno de los dos bloques de instrucciones según la condición sea verdadera o falsa.

Dentro del bloque del ELSE también puede ir cualquier tipo de instrucción, incluido otro bloque IF o del tipo que sea.

Veamos un ejemplo "especialmente malo" de un programa que nos diga el nombre de un mes a partir de su número. En temas posteriores simplificaremos bastante este problema.

CLS
INPUT "Escribe el número del mes: ", mes
IF mes = 1 THEN
        PRINT "Enero"
ELSE
        IF mes = 2 THEN
                    PRINT "Febrero"
        ELSE
                    IF mes = 3 THEN
                                PRINT "Marzo"
                    ELSE
                                IF mes = 4 THEN
                                            PRINT "Abril"
                                ELSE
                                            IF mes = 5 THEN
                                                    PRINT "Mayo"
                                            ELSE
                                                    IF mes = 6 THEN
                                                                PRINT "Junio"
                                                    ELSE
                                                                IF mes = 7 THEN
                                                                            PRINT "Julio"
                                                                ELSE
                                                                            IF mes = 8 THEN
                                                                                    PRINT "Agosto"
                                                                            ELSE
                                                                                    IF mes = 9 THEN
                                                                                                PRINT "Septiembre"
                                                                                    ELSE
                                                                                                IF mes = 10 THEN
                                                                                                            PRINT "Octubre"
                                                                                                ELSE
                                                                                                            IF mes = 11 THEN
                                                                                                                        PRINT "Noviembre"
                                                                                                            ELSE
                                                                                                                        IF mes = 12 THEN
                                                                                                                                PRINT "Diciembre"
                                                                                                                        ELSE
                                                                                                                                PRINT "Mes no válido"
                                                                                                                        END IF
                                                                                                            END IF
                                                                                                END IF
                                                                                    END IF
                                                                            END IF
                                                                END IF
                                                    END IF
                                            END IF
                                END IF
                    END IF
        END IF
END IF
PRINT "S'ACABÓ"

Muy sencillo: Si es enero lo escribimos, si no miramos si es febrero, si no a ver si es marzo, etc. así hasta diciembre. Si no es diciembre sacamos un mensaje de mes no válido. Observa que cada IF tiene su ELSE y su END IF correspondiente abajo.

Normalmente nunca llegaremos a estas estructuras tan anidadas, pero aquí se puede ver la importancia de que el tamaño de tabulación no sea muy grande.

Observa que si haces que la ventana del navegador sea más estrecha podría pasar (según los programas) que algunas líneas de las más largas pasan abajo y se nos estropea toda nuestra jerarquía. En QBasic y en los otros editores de programación esto no ocurre porque no tienen salto de línea automático para que no pase eso, pero de todas formas es muy incómodo tener que ir moviendo la barra de desplazamiento horizontal a izquierda y derecha para ver nuestro listado.



ALTERNATIVA MÚLTIPLE.
INSTRUCCIÓN ELSEIF

Vamos a arreglar un poco el ejemplo anterior para no tener tantos END IF.

CLS
INPUT "Escribe el número del mes: ", mes
IF mes = 1 THEN
               PRINT "Enero"
ELSEIF mes = 2 THEN
               PRINT "Febrero"
ELSEIF mes = 3 THEN
               PRINT "Marzo"
ELSEIF mes = 4 THEN
               PRINT "Abril"
ELSEIF mes = 5 THEN
               PRINT "Mayo"
ELSEIF mes = 6 THEN
               PRINT "Junio"
ELSEIF mes = 7 THEN
               PRINT "Julio"
ELSEIF mes = 8 THEN
               PRINT "Agosto"
ELSEIF mes = 9 THEN
               PRINT "Septiembre"
ELSEIF mes = 10 THEN
               PRINT "Octubre"
ELSEIF mes = 11 THEN
               PRINT "Noviembre"
ELSEIF mes = 12 THEN
               PRINT "Diciembre"
ELSE
               PRINT "Mes no válido"
END IF
PRINT "Se 'ACABÓ"

A la Palabra Clave ELSE le hemos colocado directamente la otra condición para simplificar un poco el Algoritmo, pero viene a ser prácticamente lo mismo. Veamos la sintaxis de forma un poco más clara:

IF condición THEN
               bloqueInstrucciones
ELSEIF otra condición THEN
               bloqueInstrucciones
ELSE
               bloqueInstrucciones
END IF

Si la condición del IF se cumple se ejecutan sus instrucciones y ya está.

Si no, se comprueba la condición del primer ELSEIF y si es verdadera se ejecutan sus instrucciones y ya está.

Si no, se comprueba la condición del siguiente ELSEIF y si es verdadera se ejecutan sus instrucciones y ya está.

Si la condición del último ELSEIF no se cumple se ejecuta el bloque ELSE si existe.

Puede haber tantos bloques ELSEIF con su condición como sea necesario, pero solo un bloque ELSE (o ninguno) al final. Si no hay bloque ELSE puede suceder que no se ejecute nada porque no se cumpla ninguna de las condiciones.

Las condiciones no tienen que estar relacionadas de ninguna forma, aquí siempre hemos preguntado por el mes, pero podíamos haber comprobado cualquier otra cosa, o poner los meses desordenados.

Esta estructura ELSEIF no se usa mucho y no existe en algunos otros lenguajes de programación, en su lugar se usan los IF anidados como vimos en el ejemplo larguísimo anterior o la estructura SELECT que veremos en el tema siguiente.

Una última cosa antes de acabar con los IF. Si escribimos ENDIF todo junto, QBasic y Visual Basic nos lo corrigen automáticamente. Esto es porque en alguna versión muy antigua del lenguaje BASIC se escribía así.


ESTRUCTURA DE SELECCIÓN SELECT

En el ejemplo de instrucciones IF anidadas nos salía un pedazo de listado para decir el nombre del mes. Después lo arreglamos un poco con las instrucciones ELSEIF. Ahora vamos a hacerlo todavía un poco mejor.

CLS
INPUT "Escribe el número del mes: ", mes
SELECT CASE mes
        CASE 1
               PRINT "Enero"
        CASE 2
               PRINT "Febrero"
        CASE 3
               PRINT "Marzo"
        CASE 4
               PRINT "Abril"
        CASE 5
               PRINT "Mayo"
        CASE 6
               PRINT "Junio"
        CASE 7
               PRINT "Julio"
        CASE 8
               PRINT "Agosto"
        CASE 9
               PRINT "Septiembre"
        CASE 10
               PRINT "Octubre"
        CASE 11
               PRINT "Noviembre"
        CASE 12
               PRINT "Diciembre"
        CASE ELSE
               PRINT "Mes no válido"
END SELECT
PRINT "S'ACABÓ"
 

Hemos usado una estructura nueva: La instrucción SELECT.

Esta estructura es equivalente a las anteriores de IF anidados, pero es más fácil de manejar y el programa queda más estructurado.

Si has entendido la estructura IF no te será muy difícil entender esta.

Lo primero es escribir las Palabras Clave SELECT CASE seguidas de una expresión. Esta expresión es normalmente simplemente una variable que puede ser de cadena o numérica. En este caso no tiene que devolver VERDADERO o FALSO como en los IF ya que no se usan operadores relacionales ni lógicos, solo los aritméticos cuando hace falta.

A continuación para cada resultado posible se pone la Palabra Clave CASE y la expresión a comparar con la del principio. Si la comparación es verdadera se ejecuta el bloque de instrucciones entre este CASE y el siguiente y se sale de la estructura. Si la condición es falsa se ejecuta el bloque del CASE ELSE si existe y si no nada.

Las expresiones de los cases se pueden poner de una de las siguientes formas:

 

CASE 1

 

Una expresión (En este caso un número), igual que en el ejemplo.

 

CASE 1, 2, 3

 

Varias expresiones separadas por comas.

CASE 1 TO 3

 

Un intervalo de valores, ambos inclusive, separados por la palabra clave TO. En este caso si la expresión inicial era de tipo entero serán válidos los resultados 1, 2 y 3, pero si era de tipo real serán válidos todos los números posibles entre el 1 y el 3 como por ejemplo el 1.517512 y el 2.17521.

 

CASE IS > 2
CASE IS = 5
CASE IS <> 8
CASE IS <= 6

Usando operadores relacionales. En el primer ejemplo serán válidos todos los valores mayores que 2, en el segundo sólo el 5, en el tercero cualquiera menos el 8 y en el último los que sean menor o igual que 6.

Si se nos olvida la palabra clave IS, QBasic la escribirá por nosotros.

Normalmente escribiremos las expresiones de los CASE de la forma más sencilla posible evitando intervalos muy extraños y teniendo cuidado con los operadores relacionales para no dejarnos "fuera" ningún valor posible, pero podemos llegar a escribir una estructura SELECT tan mal hecha como esta sin que el programa de ningún error de ejecución.

 
SELECT CASE n
        CASE 1
        CASE 1
        CASE 3
        CASE 2 TO 4
        CASE IS < 5
        CASE IS <= 5
        CASE <> 100
        CASE 16 TO 34
END SELECT

Hay expresiones repetidas, valores que entran en varias expresiones como el 3, un desastre. ¿Que ocurriría aquí?

Lo primero es que nunca ocurriría nada porque no hemos puesto bloques de instrucciones en los CASE, pero si las hubiéramos puesto pasaría lo siguiente. QBasic empieza a comprobar por los CASE hasta que encuentre uno que le venga bien. Cuando lo encuentra ejecuta su bloque de instrucciones y sale del SELECT CASE aunque otros bloques posteriores también hubieran servido. En este caso si el valor de n es 1 se ejecuta el primer CASE 1, el segundo no se llega a ejecutar nunca. Si el valor de n es 3 se ejecuta el CASE 3 y se sale, aunque los cuatro siguientes también hubieran servido. Si el valor de n es 100 no se ejecuta nada porque ningún CASE sirve y tampoco hay un CASE ELSE.

Las expresiones de los cases normalmente serán simplemente números (o cadenas) y algún intervalo alguna vez para poder estar seguro de que se va a ejecutar siempre el bloque correcto y nuestro programa va a funcionar bien.

Entre el SELECT CASE y el primer CASE no puede haber nada.

Si los bloques de instrucciones van a llevar sólo una instrucción sencilla podemos ponerla a continuación de la expresión del CASE separándola con dos puntos, por ejemplo nuestro ejemplo de los meses quedaría así:

 

SELECT CASE mes
        CASE 1: PRINT "Enero"
        CASE 2: PRINT "Febrero"
        CASE 3: PRINT "Marzo"
        CASE 4: PRINT "Abril"
        CASE 5: PRINT "Mayo"
        CASE 6: PRINT "Junio"
        CASE 7: PRINT "Julio"
        CASE 8: PRINT "Agosto"
        CASE 9: PRINT "Septiembre"
        CASE 10: PRINT "Octubre"
        CASE 11: PRINT "Noviembre"
        CASE 12: PRINT "Diciembre"
        CASE ELSE: PRINT "Mes no válido"
END SELECT

 

con lo que conseguimos un listado casi la mitad más corto.

Por supuesto las expresiones también pueden ser de cadenas:

 

INPUT "Escribe el nombre de un periférico del ordenador: ", perif$
SELECT CASE perif$
        CASE "Teclado", "Ratón"
               PRINT "Es un periférico de entrada"
        CASE "Monitor", "Impresora"
               PRINT "Es un periférico de salida"
        CASE "Módem"
               PRINT "Es un periférico de entrada/salida"
        CASE ELSE
               PRINT "Este periférico no lo conozco"
END SELECT

 

Y por supuesto los bloques de instrucciones de los CASE pueden contener cualquier tipo tipo de instrucciones anidadas en su interior como bloques IF, otro SELECT, etc.

Si estos bloques se hacen muy largos no te asustes, solucionaremos el problema cuando lleguemos a Programación Modular donde el SELECT servirá como menú para dar entrada a distintos procedimientos o subprogramas.

Casi todos los lenguajes tienen una estructura equivalente a SELECT, pero en el caso del lenguaje C es bastante mala. Hay que tener en cuenta de que en los lenguajes de los sistemas de bases de datos (SQL) existe una instrucción SELECT que no tiene nada que ver con esto, sirve para sacar información de las bases de datos.