Herramientas de usuario

Herramientas del sitio


curso-cpp:estructuras-selectivas

¡Esta es una revisión vieja del documento!


Estructuras de control selectivas [En construcción]

Hasta ahora, la lista de instrucciones de nuestro programa que se ejecutarán está fija: Esto es, siempre especificamos una lista de instrucciones, y cada una de ellas es ejecutada en orden, de arriba hacia abajo.

Hay veces en las que solamente queremos llevar a cabo una acción determinada a veces, cuando se cumple una cierta condición particular que hace que queramos llevar a cabo la tarea. Veremos en esta lección cómo se puede lograr esto en C++.

La instrucción if

La instrucción if sirve para instruir a la computadora a que lleve a cabo un determinado conjunto de instrucciones, únicamente cuando se cumpla una condición específica.

Versión común

La sintaxis (forma de escritura) de la instrucción if es la siguiente:

if (condicion)
{
    instruccion1;
    instruccion2;
    ...
    instruccionFinal;
}

Notar que los paréntesis alrededor de la condición son obligatorios. De manera similar a lo que ocurre en main, donde escribimos todas las instrucciones que queremos que se ejecuten, las llaves { y } delimitan un bloque de instrucciones, que únicamente se ejecutarán cuando se cumpla la condición. Si la condición no se cumple, se saltearán todas las instrucciones encerradas entre llaves.

Por ejemplo, el siguiente programa puede utilizarse para leer un número, y escribir en pantalla un mensaje de acuerdo a su signo:

#include <iostream>

using namespace std;

int main()
{
    int x;
    cin >> x;
    if (x > 0)
    {
        cout << "El numero " << x << " es positivo." << endl;
    }
    if (x < 0)
    {
        cout << "El numero " << x << " es negativo." << endl;
    }
    return 0;
}

Notar algo muy importante, que es que indentamos (colocamos espacios a la izquierda de) las instrucciones del if que encerramos entre llaves: Esto lo hacemos por claridad, para que sea mucho más fácil leer los programas. Cada vez que ponemos un bloque de instrucciones entre llaves, es conveniente que todas las instrucciones contenidas estén más a la derecha visualmente que las instrucciones que rodean al bloque, para que sea más fácil entender a simple vista dónde comienza y termina el bloque de instrucciones del if. Notar que al compilador no le importan los espacios, y únicamente se basa en las llaves para decidir hasta dónde llega el if. Pero es importante para poder leer y entender más fácil el código, utilizar prolijamente los espacios.

Vemos aquí nuestro primer ejemplo de condición: x > 0 es una condición que puede colocarse en un if (entre paréntesis), y que se cumple justamente cuando la expresión x es mayor que cero. Como x es directamente una variable con el valor que leímos, esto se cumplirá cuando el número ingresado por el usuario sea mayor que cero. En dicho caso (¡y solo en dicho caso!) el programa ejecutará las instrucciones entre llaves que siguen al if. En este caso, es una única instrucción que muestra un mensaje indicando que el número es positivo.

Similarmente, luego de verificar la primera condición y (quizás) ejecutar lo indicado entre llaves, se llega en el programa al segundo if: En este se verifica la condición x < 0, y por lo tanto las instrucciones entre llaves que siguen a este if únicamente serán ejecutadas cuando el número ingresado sea negativo.

Por ejemplo, si ingresamos el número 4 veremos en pantalla al ejecutar la siguiente interacción:

4
El numero 4 es positivo.


------------------
(program exited with code: 0)
Press return to continue

En cambio, si ingresamos un valor de -2, al ejecutar veremos en pantalla lo siguiente:

-2
El numero -2 es negativo.


------------------
(program exited with code: 0)
Press return to continue

Si ingresamos un valor 0, veremos lo siguiente:

0


------------------
(program exited with code: 0)
Press return to continue

¡Vemos en este caso que el programa no imprime ningún mensaje! ¿Por qué ocurre esto?

La computadora ejecuta las instrucciones indicadas una por una en orden. En particular, cuando llega a cada if, verifica la condición correspondiente para ver si se cumple, y solo ejecuta la instrucción entre llaves (de impresión del mensaje) cuando la condición se cumple. Por lo tanto si este programa no imprime nada, debería ser porque cuando se ingresa el valor 0, ninguna de las dos condiciones se cumple, y no se ejecuta ninguno de los ifs.

En efecto, cero es un número especial, el único entero que no es ni positivo ni negativo, y por lo tanto 0 < 0 y 0 > 0 son ambas falsas. Podemos entonces agregar este caso como un nuevo if en el programa:

#include <iostream>

using namespace std;

int main()
{
    int x;
    cin >> x;
    if (x > 0)
    {
        cout << "El numero " << x << " es positivo." << endl;
    }
    if (x < 0)
    {
        cout << "El numero " << x << " es negativo." << endl;
    }
    if (x == 0)
    {
        cout << "El numero ingresado es cero." << endl;
    }
    return 0;
}

Si ejecutamos ahora los mismos ejemplos de antes, obtendremos los mismos resultados en los primeros dos casos: pero al ingresar el valor cero, ahora observaremos lo siguiente:

0
El numero ingresado es cero.


------------------
(program exited with code: 0)
Press return to continue

Notar que en nuestra tercera condición, hemos utilizado por primera vez el operador ==: Este operador no tiene nada que ver con el =: Recordemos que el operador = se utiliza para la asignación de variables (“meter valores en cajas”). El == en cambio se utiliza para expresar condiciones, y funciona como la igualdad matemática.

El == es un ejemplo de los que de denominan operadores de comparación. Los veremos en más detalle muy pronto.

Veamos un segundo ejemplo de programa, que muestre un mensaje de acuerdo a la paridad del número ingresado:

int main()
{
    int x;
    cin >> x;
    if (x % 2 == 0)
    {
        cout << "El numero " << x << " es par." << endl;
    }
    if (x % 2 == 1)
    {
        cout << "El numero " << x << " es impar." << endl;
    }
    return 0;
}

Recordemos que % es el operador de “resto de la división”, también llamado módulo. Para saber si un número es par o impar, debemos considerar el resto de la división por 2. Cuando el resto sea 0, el número es par, y cuando sea 1, es impar. Esas son las condiciones que verificamos en los ifs de este programa, y en cada caso, imprimimos un mensaje apropiado para la condición que se cumple.

El else

En el último ejemplo, verificábamos si un número era par o impar, e imprimíamos un mensaje de acuerdo a la paridad. Notemos que en este caso tenemos dos opciones excluyentes: O bien el número es par, y entonces solamente se imprime el mensaje para el caso par, o bien esto no ocurre(porque el número es impar), y entonces solamente se imprime el mensaje para el caso impar.

Esta situación, en la cual hay una cierta condición, y se debe ejecutar un conjunto de instrucciones cuando se cumple la condición, y otro conjunto cuando no se cumple, es muy común. Para ello existe una parte opcional de la instrucción if, que hasta ahora no hemos utilizado, y es la sección else.

Es posible escribir lo siguiente:

if (condicion)
{
   instruccionA1;
   instruccionA2;
   instruccionA3;
   ...
}
else
{
   instruccionB1;
   instruccionB2;
   instruccionB3;
   ...
}

En este caso, el primer bloque de instrucciones (instruccionA1, instruccionA2, etc) corresponde al “if normal”, y se ejecutará cuando la condición indicada entre paréntesis ocurra. En cambio, el segundo bloque de instrucciones (instruccionB1, instruccionB2, etc) se pone a continuación de else, y se ejecuta cuando la condición del if no ocurre. De esta forma, uno solo de los bloques de instrucciones será ejecutado, dependiendo de si la condición del if vale o no.

A continuación mostramos el ejemplo anterior de par o impar, reescrito utilizando la instrucción else:

int main()
{
    int x;
    cin >> x;
    if (x % 2 == 0)
    {
        cout << "El numero " << x << " es par." << endl;
    }
    else
    {
        cout << "El numero " << x << " es impar." << endl;
    }
    return 0;
}

En este caso, en lugar de utilizar un segundo if con la condición (x % 2 == 1), como esta condición es la que ocurre exactamente cuando no ocurre la primera, podemos simplemente extender el primer if con un else, para indicar qué hacer cuando el número no es par (en cuyo caso, será impar).

Operadores de comparación

Para expresar las condiciones anteriores, hemos utilizado los operadores <, >, e ==. Estos operadores se utilizan para expresar condiciones, mediante la comparación de otros dos valores. Así, x > 10 expresa la condición de que el valor almacenado en x debe ser mayor que 10. Similarmente, x + y == z expresa la condición de que el valor almacenado en x, más el valor almacenado en y, debe ser igual al valor almacenado en z.

Estos operadores se llaman operadores de comparación. A continuación mostramos los más importantes operadores de comparación, junto a un texto que indica su significado:

== "Igual a"
!= "Distinto de"
<  "Menor a"
>  "Mayor a"
<= "Menor o igual a"
>= "Mayor o igual a"

Cada uno de estos operadores puede utilizarte para comparar los valores de dos expresiones, obteniéndose así una condición que puede utilizarse en un if. Recordar siempre que el operador de comparación “==”, y el operador de asignación “=” son completamente diferentes, y mezclarlos puede llevar a errores en el comportamiento del programa.

Versión con una única instrucción

Hemos visto que la sintaxis (escritura) completa del if tiene la siguiente forma:

if (condicion)
{
    instrucciones;
}
else
{
    instrucciones;
}

Además, ya hemos mencionado que la parte del else, para especificar qué hacer cuando no se cumple la condición, es opcional. Una opción adicional que existe en C++ en el caso del if (o el else), es la de no utilizar las llaves cuando el bloque de instrucciones que delimitan contiene una sola instrucción. En este caso, si no usamos llaves, C++ asumirá que la primera instrucción que sigue a continuación conforma el bloque completo.

Veamos algunos ejemplos:

// Escritura completa
if (x > 0)
{
    cout << "El numero es positivo" << endl;
}
cout << "Fin del programa" << endl;

// Escritura sin llaves
if (x > 0)
    cout << "El numero es positivo" << endl;
cout << "Fin del programa" << endl;

Los dos ejemplos anteriores son equivalentes, ya que hay una sola instrucción entre llaves. Notemos en cambio que los siguientes dos ejemplos no son equivalentes:

// Escritura completa
if (x > 0)
{
    cout << "El numero ";
    cout << "es positivo" << endl;
}
cout << "Fin del programa" << endl;

// Escritura sin llaves:
// CAMBIA EL SIGNIFICADO! 
// Las llaves anteriores NO SE PUEDEN OMITIR.
if (x > 0)
    cout << "El numero ";
    cout << "es positivo" << endl;
cout << "Fin del programa" << endl;

// La version anterior sin llaves equivale a esto:
if (x > 0)
{
    cout << "El numero ";
}
cout << "es positivo" << endl;
cout << "Fin del programa" << endl;

En el ejemplo anterior, vemos que omitir las llaves cuando el bloque de instrucciones que queremos ejecutar tiene más de una instrucción es un error. Solamente es posible omitir las llaves, cuando el bloque tiene una única instrucción. Ante la duda, o posibilidad de confusión, es mejor dejar las llaves aunque se utilice una única instrucción, para evitar problemas.

Existe un peligro más cuando omitimos las llaves, y este peligro es el resultado de que en C++ la parte else sea opcional. Supongamos un código como el siguiente:

// Ejemplo 1 (resulta correcto)
if (x > 0)
    if (x % 2 == 0)
        cout << "Positivo par" << endl;
    else
        cout << "Positivo impar" << endl;
   
// Ejemplo 2 (resulta incorrecto)

if (x > 0)
    if (x % 2 == 0)
        cout << "Positivo par" << endl;
else
    cout << "Negativo" << endl;

Notemos que, más allá de los mensajes que se van a mostrar, la única diferencia entre el primer y el segundo ejemplo es la indentación (cantidad de espacios a la izquierda) del else. Pero al compilador no le importa la cantidad de espacios. Por lo tanto, ambos casos son interpretados de idéntica manera. En este caso... ¿Corresponde para C++ el else al primer if, como querríamos en el ejemplo2, o corresponde al segundo, como querríamos en el ejemplo 1?

La regla que sigue C++, que determina cómo resolver esta confusión cuando no se usan llaves en el if, es que un else en el código corresponde al if inmediatamente anterior. Es decir, el compilador interpreta la situación como querríamos en el ejemplo 1, con lo cual el ejemplo 2 nos resulta incorrecto. Para escribir lo que querríamos en el ejemplo 2, es necesario sí o sí utilizar llaves.

Veamos a continuación entonces cómo escribir los ejemplos:


Operadores lógicos

El tipo bool

El tipo bool

curso-cpp/estructuras-selectivas.1475787152.txt.gz · Última modificación: 2016/10/06 20:52 (editor externo)