4 - Bloques condicionales y mecanismos de decisión
En este capítulo presentaré unas de las estructuras más usadas en cualquier lenguaje de programación, que nos serán muy útiles en especial para tomar decisiones. Hasta ahora nuestro programa era totalmente secuencial, le presentabamos una serie de instrucciones y él las ejecutaba en fila. Ahora es el momento de que el programa sea capaz de decidir si hay ciertas líneas que no se tienen que hacer, o bien si tiene que tomar un camino distinto en vez de aplicar todas las instrucciones.
Pero antes de meternos en faena quiero extender un poco más nuestro abanico de variables e introducir dos más. Una de ellas nos será útil para casi cualquier programa y la otra está íntimamente ligada al uso de bloques condicionales, que es el grueso de esta lección.
variables char
char letra;
letra = 'A';
Una variable char almacena un caracter. Sólamente uno, no podeis poner dos letras dentro de un char. Fijaos en el detalle de que la asignación de un valor a un char exige que el caracter esté entre comillas simples, al contrario de las cadenas de texto, como la que se meten en fprintf y fscanf, que son con comilla doble.
Algunos ya habeis usado sin daros cuenta este tipo de variable cuando poníais tildes en un texto de fprintf, de este modo:
fprintf ("Hola qu%c tal", 130);
En este caso justamente después de la letra u se inserta una variable %c, que corresponde a char, y su valor es 130. Qué es este 130? es la posición de "e minúscula con tilde" en la tabla ascii. En resumen:
-
char define una variable de tipo caracter.
-
las asignaciones de valor se utilizan con comillas simples.
-
el símbolo de inserción de un char es %c.
variables bool
Una variable tipo int ocupa 16 bit, por lo tanto puede almacenar hasta 216 valores distintos. Un bool es una variable que ocupa un solo bit, por lo tanto solo dos valores son posibles. Es por ello por lo que bool se usa para almacenar númueros lógicos, es decir sí o no, verdadero o falso, true or false
bool condicion1;
bool condicion2;
condicion1 = 1; //true
condicion2 = 0; //false
El número 0 es el único que hará que el valor del bool almacene false, cualquier otra cosa será true.
condicion1 = 'a'; //equivale a true
condicion2 = 4.2; //equivale a true
Esto puede sonar un poco confuso ahoira pero se despejará a continuacion en los bloques if. Simplemente pensad en un hueco de la memoria de un sólo bit, por lo que solo puede almacenar un 1 lógico o un 0 lógico, que nosotros traducimos en true o false a efectos de programación. Al contrario que el resto de variables, bool no suele imprimirse por pantalla en ninguna ocasión, asi que no merece la pena saber con qué '%' se inserta en los fprintf.
operadores lógicos
Anteriormente se explicaron los operadores aritméticos, +, -, * etc... Existen muchos más operadores y por ahora vamos a ver otra familia, los operadores lógicos, que se encargan no de operar números, sino de compararlos.
// El operador == es 'igual', compara dos números y devuelve true si son iguales, false en cualquier otro caso.
bool a = (45 == 45 ) ; // true
bool b = (12 == 45 ) ; // false
bool c = ('a' == 'b' ) ; // false
// El operador != es 'desigual', devuelve true cuando los números son distintos.
bool d = (12 != 45 ) ; // true
// El operador > es 'mayor que', devuelve true cuando el primer número es mayor que el segundo.
bool e = (12 > 45 ) ; // false
Del mismo modo, < es 'menor que', y >= y <= son respectivamente 'mayor o igual' y 'menor o igual'. Para recordar el orden de los símbolos pensad que se escriben igual que se leen.
Otro grupo dentro de los operadores lógicos son:
// El operador ! 'not', niega lo que venga a continuacion y devuelve el resultado contrario
bool f = !(12 == 12); //false
// El operador && 'and' devuelve true sí y sólo sí las dos condiciones de sus lados son true
bool g = (12 == 12) && (32 > 21); //true
bool h = (12 != 54) && (2 >= 21); // false
//El operador || 'or' devuelve false sí y sólo sí todas las condiciones son falsas.
bool i = (12 == 12) || (12 > 21); //true
bool j = (23 == 76) || (12 > 21); //true
Estos dos ultimos operadores son muy fáciles de recordar, simplemente leedlos en voz alta en tono interrogativo, por ejemplo la variable i sería "es doce igual a doce ó doce mayor que veintiuno?" la primera condición es verdadera, por tanto sí.
Por supuesto, en todos estos ejemplos he usado números, que en el caso de programas reales serán variables. Un pequeño consejo: Si comparais una variable con un número, poned primero el número. Es decir así:
bool x = (12 == num);
Y no así:
bool x = (num == 12);
La razón es muy sencilla. En algunas ocasiones te olvidas del segundo = del operador y entonces haces una asignación. Si me equivoco y pongo esto:
bool x = (num = 12);
cambiaré el valor de num a 12 y además una asignación devuelve siempre true, por lo que la condición será siempre verdadera, sin embargo si pongo esto:
bool x = (12 = num);
Dará un error al compilar, porque '12' no es ninguna variable, es un número, y no puedes cambiar su valor.
el bloque if-else
Por fin vamos a darle uso real a los bool. Un bloque condicional if hace que el programa haga (o no) una serie de instrucciones:
if (var == 12){
//instruccion 1
//instruccion 2
//instruccion n
}
//el programa sigue...
En este ejemplo, la comprobación que hacemos es que una variable llamada 'var' que habremos creado antes sea igual que doce. Que es verdadero? entonces ejecuta las instrucciones dentro de las llaves {}. Que no lo es? entonces ignóralas y continua con el programa. Recordad no poner el ; después de un if.
El contenido de los paréntesis de un if es siempre un bool, vamos hay que meter tru o false de alguna manera, pero hemos visto que los operadores lógicos siempre devuelve un bool, y que cualquier cosa que no sea 0 va a retornar true, por ejemplo
if (4){ //entra
}
if ('s'){ //entra
}
if (!5){ //no entra (not 5 devuelve 0, por tanto false)
}
En ocasiones se necesita que cumplida cierta condición se hagan ciertas acciones, y en el caso de que no se cumpla otras. Podríis pensar que una manera de hacer esto es así:
if (var > 12){
// cosas...
}
if ( ! (var > 12)){
// otras cosas
}
Pero existe otro método mejor, y es el bloque else(si no). else siempre debe ir justo después de un if, y se entrará en else cuando no se haya entrado en if. El código anterior quedaría:
if (var > 12){
// cosas...
}
else{
// otras cosas
}
operador ternario
El operador ternario es una especie de if-else comprimido en una línea. Util cuando solo se desea hacer una acción dentro del if y otra distinta dentro del else. Su modo de uso es este:
// expresión boleana ? valor si cierto : valor si falso
(var1 > 2) ? var2 = 0 : var2 = 1;
En este caso se comprueba si var1 es mayor que 12. El el caso de que sea cierto, a otra variable var2 se le asignará el valor 0, y si es falso, var2 será 1.
switch
Por último, el bloque switch nos sirve para evitar tener muchos if seguidos, algo parecido a esto:
if (var == 1){
// cosas...
}
if (var == 2){
// cosas...
}
if (var == 3){
// cosas...
}
if (var == 4){
// cosas...
}
En su lugar, la manera elegante de hacer lo mismo es con switch, de este modo:
switch (var) {
case 1:
//cosas
break;
case 2:
//cosas
break;
case 3:
//cosas
break;
case 4:
//cosas
break;
}
En los paréntesis de switch se especifica siempre una variable, la que querramos comparar, y a continuación tantos bloques de 'case' como necesitemos. Los cases tienen una sintaxis algo rara, en vez de delimitarlos con llaves {}, empiezan con dos puntos : y terminan siempre con uns intrucci break;. No poner el break; haría que se ejecutasen todas las acciones a partir de la primera cierta.
deberes lección 4
-Recordais los ejercicios de otras lecciones que quedaron incompletos? mas concretamente estos:
Realizar un programa completo que pida al usuario dos números por teclado y realice las cuatro operaciones básicas con ellos. El programa debe presentar por pantalla los resultados. El resultado deberia ser algo parecido a esto: http://i.imgur.com/kTq5uLv.png
Crear un programa que pregunte por los dos catetos de un triángulo rectángulo y calcule la hipotenusa. Posteriormente debe calcular los dos ángulos restantes terminando de resolver el triángulo e imprimir todos los resultados por pantalla.
Crear un programa que pregunte un número entero de tres cifras y desglose en numero en centenas unidades y decenas, es posible hacerlo tan solo con int. Ejemplo de resultado: http://puu.sh/6PI58.png
En los tres casos siempre habia la posibilidad de que el usuario trolleara y metiese números que pueden causar error al programa (divided by zero, o un cateto negativo, o un numero de mas de 3 cifras...) Ahora podemos tomar decisiones analizando variables, por lo que el ebjetivo es ahora rehacer estos tres programas, pero que comprueben previamente si el valor introducido es correcto. En el caso de que lo sea continuar la ejecución normalmente, y en caso negativo alertar al usuario de que ha habido un error y se reiniciará el programa automáticamente (esto ultimo podeis hacerlo con system()).
-Crear un programa que pida una letra por teclado e indique al usuario si el caracter obtenido es mayúscula o minúscula.
-Crear una mejora del programa anterior que pida un caracter por teclado e indique al usuario si el caracter obtenido es una letra, un número o cualquier otro símbolo.
-Cuales son los resultados de estas operaciones logicas?
((12>2) || (3<=1)) && (23!=23)
!(4 == 1) || (!12 == !0)
(a == b) && (a < b)
(a == b) || (a < b)
-Hacer otro programa tipo calculadora, pero que esta vez pida los dos numeros y la operacion a realizar. La operacion puede ser un caracter y las posibles entradas los caracteres '+', '-'... etc. Si os quereis flipar un poco podeis hacer que tambien haga potencias, raices, senos... y si hace operaciones que solo exigen un numero de entrada que no pregunte el segundo.
-Más triágulos. Esta vez hacer un programa que decida si el triangulo introducido (3 lados) es equilátero, isósceles o escaleno, comprobar que efectivamente esos lados forman un triangulo url=http://puu.sh/6YhWp.jpg [/url] y si os sentis valurosos, calcular el área
-Un programa que diga si el número introducido es divisible por 2, 3, 5 y 7.