Control Flujo Condicional
Control Flujo Condicional
Control Flujo Condicional
5
5.1 Introducción
Los programas vistos hasta el momento se ejecutan de forma secuencial, una sentencia a continua-
ción de otra sin omitir ninguna.
Estas sentencias, asociadas a la función principal main(), constituyen un ejemplo de sentencia
compuesta: conjunto de sentencias situadas dentro de un bloque de código entre llaves { }.
La programación limitada a la ejecución secuencial de instrucciones es demasiado simple. Las
capacidades que vemos día a día en nuestra interacción con los ordenadores y las aplicaciones
informáticas, serían imposibles si solamente contáramos con las opciones vistas hasta el momento.
Es suficiente la introducción de dos nuevas estructuras básicas para que se abra la puerta a la
posibilidad de realizar todas las tareas de cómputo que son teóricamente concebibles.
Estas dos estructuras, constituidas por sentencias compuestas, son:
las estructuras condicionales
las estructuras iterativas o bucles
Sirven para alterar la estructura secuencial que se tiene por defecto.
Una sentencia condicional realiza un conjunto u otro de sentencias dependiendo del cumplimiento
o no de una determinada condición.
En C++ podemos distinguir diferentes tipos:
Simple: if
Ampliada: if - else
Anidada: if – else if - . . . - else
Multisalida: switch
Además de las sentencias de control de flujo condicional, introduciremos algunos de los opera-
dores típicamente asociados a éstas.
1
Fundamentos de Programación en C++, Curso 2020/21
Sirven para comparar dos variables o expresiones. La expresión boolena resultante en la que
intervienen puede resultar cierta (true) o falsa (false).
C++ utiliza el tipo de dato nativo bool para almacenar los valores true o false de una expresión
boolena. En la práctica, C++ lo que hace es lo siguiente:
si la expresión en la que interviene el operador es falsa, internamente se almacenará un 0.
si la expresión se evalúa como cierta, se almacenará un 1.
Las palabras reservadas true y false son literales predefinidos por el lenguaje con el objetivo de
aportan legibilidad y contexto a las expresiones booleanas.
#include <iostream>
using namespace std;
int main()
{
int x = 3;
int y = 4;
bool z = x > y; // z tomará el valor false
cout << z << endl;
z = x != y; // z tomará el valor true
cout << z << endl;
}
Es una sentencia en la que se evalúa una condición y, solo si es verdad, se ejecuta un conjunto de
sentencias asociadas.
if (condicion)
{
bloque de sentencias;
}
Ejemplo
/*----------------------------------------------------*/
/* Este programa transforma temperaturas de */
/* grados celsius a grados kelvin */
/* Comprueba si la temperatura tiene existencia real */
/*----------------------------------------------------*/
#include <iostream>
using namespace std;
int main()
{
double centig;
cout << "Introduzca grados celsius: ";
cin >> centig;
if (centig >= -273.)
{
double kelvin = centig + 273.; // Inicializacion
cout << centig << " grados celsius son " << kelvin
<< " grados kelvin\n";
}
}
Nótese en el ejemplo anterior que las dos sentencias asociadas a la sentencia if se ejecutan en
función de si la expresión entre paréntesis centig >= -273. es evaluada como cierta o falsa.
Consideraciones respecto a la sintaxis
Cuando el bloque está formado por una única sentencia, pueden omitirse las llaves.
Así,
if (a != 0)
{
a = 1/a;
}
es equivalente a:
if (a != 0)
a = 1/a;
if (a) // a != 0 <-> a
a = 1/a;
dado que cualquier valor no nulo será siempre evaluado como cierto.
La forma ampliada permite ejecutar dos bloques de sentencias distintas dependiendo de que se
cumpla la condición o no.
if (condicion)
{
bloque de sentencias 1;
}
else
{
bloque de sentencias 2;
}
Ejemplo 1
/*----------------------------------------------------*/
/* Grados celsius -> grados kelvin */
/* Comprueba si la temperatura tiene existencia real */
/* En caso negativo visualiza un mensaje de error */
/*----------------------------------------------------*/
#include <iostream>
using namespace std;
int main()
{
double centig;
cout << "Introduzca grados celsius: ";
cin >> centig;
Ejemplo 2
#include <iostream>
using namespace std;
int main()
{
double x = 0.3;
double y = 0.1;
double z = 0.2;
int main()
{
double x = 0.1 + (0.2 + 0.3);
double y = (0.1 + 0.2) + 0.3;
// Fija 20 posiciones a visualizar despues de la coma
cout.precision(20);
cout << "x=" << x << "\ny=" << y << endl;
if (a != 0)
{
b = a;
a = 1/a;
};
else
cout << "No se puede invertir el 0\n";
El ; tras la llave de cierre } es la causa del error. Podemos reescribir el código como:
if (a != 0)
{
b = a;
a = 1/a;
}
;
else
cout << "No se puede invertir el 0\n";
Así se aprecia mejor que la sentencia vacía ; hace que el else quede desvinculado del if.
Otro error sintáctico típico es olvidar las llaves {...}.
if (a != 0)
b = a;
a = 1/a;
else
cout << "No se puede invertir el 0\n";
if (a != 0)
b = a;
a = 1/a;
else
cout << "No se puede invertir el 0\n";
Así se aprecia mejor que la sentencia a = 1/a; no pertenece al bloque if y, de nuevo, el else queda
desvinculado.
if (a != 0)
;
{
b = a;
a = 1/a;
}
Ahora resulta que la única sentencia asociada al if es la sentencia vacía ;. El bloque de sentencias
entre llaves {...} se ejecutará siempre.
Los errores semánticos son en muchas ocasiones los más complejos de depurar, pues pasan des-
apercibidos para el compilador y sólo son detectables a través de la salida espuria del programa.
En muchas ocasiones interesa evaluar de forma anidada varias expresiones condicionales de arriba
a abajo. Cuando aparece una condición verdadera, ejecuta las acciones asociadas y salta el resto de
las expresiones condicionales sin necesidad de evaluarlas.
Normalmente existe un bloque final else{. . . } que actúa como condición por defecto.
if (condicion_1)
{
bloque 1 de sentencias;
}
else if (condicion_2)
{
bloque 2 de sentencias;
}
else if (condicion_3)
{
bloque 3 de sentencias;
}
// Tantos bloques else if como sean necesarios
else // si no se cumple ninguna de las anteriores
{
bloque n de sentencias;
}
Nótese que no se está introduciendo ninguna novedad sintáctica en el lenguaje. Para comprobarlo,
basta reorganizar visualmente esta sentencia compuesta en forma anidada a la forma ampliada.
Por ejemplo, para 4 bloques de sentencias, los bloques anidados en forma ampliada quedarían
visualmente así:
if (condicion_1)
{
bloque 1 de sentencias;
}
else
{
if (condicion_2)
{
bloque 2 de sentencias;
}
else
{
if (condicion_3)
{
bloque 3 de sentencias;
}
else // si no se cumple ninguna de las anteriores
{
bloque 4 de sentencias;
}
}
}
Ejemplo
if (n > 0)
if (a > b)
z = a;
else
z = b;
Su versión sangrada permite visualizar de forma más clara las intenciones del programador:
if (n > 0)
if (a > b)
z = a;
else
z = b;
Nótese que el bloque else siempre está asociado al if inmediatamente anterior. Por ello, si en el
ejemplo anterior, lo que realmente se desea es asociar el else al primer if, la solución sería:
if (n > 0)
{
if (a > b)
z = a;
}
else
z = b;
La siguiente tabla muestra dos escenarios en los cuales la salida del programa será idéntica si el
conjunto de condiciones es mutuamente excluyente.
Opción 1 Opción 2
if (condicion_1) if (condicion_1)
{ {
bloque 1 de sentencias; bloque 1 de sentencias;
} }
else if (condicion_2) if (condicion_2)
{ {
bloque 2 de sentencias; bloque 2 de sentencias;
} }
// Resto de bloques else if // Resto de bloques if
else if (condicion_n) if (condicion_n)
{ {
bloque n de sentencias; bloque n de sentencias;
} }
Sirven para evaluar expresiones compuestas de tipo lógico, cuya resultado, por tanto, resultará
cierto o falso, true o false.
La evaluación de las operaciones lógicas se realiza de izquierda a derecha y se interrumpe cuando
se ha asegurado el resultado. Esto se conoce como propiedad de cortocircuito: si se puede con-
cluir el valor lógico del resultado a partir de una evaluación parcial de la expresión, no se sigue
evaluando la misma.
Los operadores de comparación y lógicos aparecen habitualmente de forma simultánea en las ex-
presiones. Por ello, es conveniente conocer su orden de precedencia relativo:
Insistimos en usar los paréntesis (...) en caso de duda y/o para mejorar la legibilidad.
Ejemplo 1
int main()
{
int x, y;
cout << "Introduce dos numeros enteros positivos o 0. "
<< "Ambos no pueden valer simultáneamente 0.\n";
cout << "Introduce el primer numero: ";
cin >> x;
cout << "Introduce el segundo numero: ";
cin >> y;
if (x < 0 || y < 0)
cout << "Error. Los numeros introducidos no son ambos positivos.\n";
else if (x == 0 && y == 0)
cout << "Error. Los dos numeros son 0.\n";
else
cout << "Los numeros introducidos son validos.\n";
}
Ejemplo 2
int main()
{
int x, y;
cout << "Introduce el numerador: ";
cin >> x;
cout << "Introduce el denominador: ";
cin >> y;
if (!y) // Equivalente a if (y != 0)
cout << "Error. No podemos dividir por 0.\n";
else
cout << "x/y= " << x/y << endl;
}
Aunque el escalonamiento if - else if - else puede evaluar de forma anidada múltiples condi-
ciones, si estas son muy numerosas, empieza a haber pérdida de legibilidad.
C/C++ posee una estructura condicional múltiple, switch, que ejecuta un bloque de sentencias si
una variable o expresión entera coincide con alguno de los valores proporcionados en una lista
de constantes enteras (literales int o char, por ejemplo).
switch (expresion)
{
case valor_1:
sentencias_1
case valor_2:
sentencias_2
//Resto de bloques case
case valor_n:
sentencias_n
default:
sentencias_default;
}
La ejecución del programa consiste en comparar expresion de arriba a abajo con cada constante
literal que aparece tras la palabra reservada case. Si se localiza una coincidencia, se ejecutan todas
las sentencias por debajo de esa constante hasta:
finalizar el bloque switch
encontrar una sentencia break;
Opcionalmente se puede insertar una condición por defecto mediante default, cuyas sentencias
asociadas se ejecutarían si no se ha encontrada previamente una coincidencia.
Para ilustrar el funcionamiento de la sentencia switch vamos a ver diferentes versiones de un
programa con idéntica salida por pantalla, que muestra el númer de días de un mes.
Versión 1 con if anidados
#include <iostream>
using namespace std;
int main()
{
cout << "Dame el mes: (1, 2, ..., 12): ";
int mes;
cin >> mes;
#include <iostream>
using namespace std;
int main()
{
cout << "Dame el mes: (1, 2, ..., 12): ";
int mes;
cin >> mes;
#include <iostream>
using namespace std;
int main()
{
cout << "Dame el mes: (1, 2, ..., 12): ";
int mes;
cin >> mes;
La sentencia condicional switch se utiliza con frecuencia para gestionar la selección en menús.
En caso de que la opción elegida no sea válida, se realiza el código asociado al bloque default,
visualizándose un mensaje de error.
Ejemplo de menú