13 de junio de 2016

La estructura de control if.

   La estructura de control if tiene la siguiente estructura general:

                    if (expresión) {
                        sentencia(s);
                   }

   La estructura de selección if procesa o ejecuta el grupo de sentencia(s) (puede ser cualquier sentencia(s) válida(s) en el lenguaje de programación C, como por ejemplo, otras estructuras de control (de selección y de repetición), incluida ella misma, a lo cual se le denomina: estructuras de control anidadas) delimitadas por su bloque, si al evaluar la expresión es distinta de cero, es decir: expresión != 0.

   La llave izquierda “{” indica el inicio del bloque correspondiente a la estructura, mientras que la llave derecha “}” delimita su final.

   Si al ser evaluada la expresión ésta es igual a cero, se ignora el grupo de sentencia(s) delimitadas por el bloque de la estructura, es decir, no se procesan (no son ejecutadas), y la ejecución continúa con la primera sentencia que se encuentre después del delimitador de fin de bloque del if.

   El Ejemplo 3.1, además de mostrar el funcionamiento de la estructura de selección if, muestra el uso de los operadores relacionales presentados en la siguiente tabla:

Operador     Descripción
  ==            Igual que
    !=             Distinto de
                  <              Menor estricto que
                  >              Mayor estricto que
                <=             Menor o igual que
                >=             Mayor o igual que

   A partir del Ejemplo 3.1 sólo se hará mención explícita de las líneas de código que introduzcan algún elemento nuevo o diferente respecto de lo hasta ahora comentado en los ejemplos y entradas anteriores con la finalidad de hacer más ágil la explicación.

   Lo primero a comentar aparece en la línea 12, la cual introduce una nueva modalidad en la lectura de datos a través de la función scanf: es posible leer más de un dato en un solo llamado a la función. Los dos especificadores de formato “%d” le indican a la función scanf que lea dos enteros decimales de la entrada estándar.

   Observe que al igual que con la función printf, por cada especificador de formato debe existir su correspondiente variable asociada para su almacenamiento, y es responsabilidad del programador el que también exista una correspondencia entre el especificador de formato y el tipo de dato de la variable.

   Por otro lado, la línea 14 muestra el uso de la estructura de selección if y el operador relacional de igualdad==”. La forma de interpretar en nuestro lenguaje dicha sentencia es: “Si num1 es igual que num2, ejecuta la sentencia de la línea 15”.

  No está de más volver a enfatizar que las llaves ({ }) delimitan el bloque de código asociado a la correspondiente estructura de control. Una práctica muy común en C y que se recomienda usar con precaución o preferiblemente no utilizar, es la omisión de los delimitadores de bloque para las estructuras de selección y repetición, si se omiten, únicamente se considera, como parte de la estructura de control, la sentencia inmediata posterior a ella, ninguna otra, sin importar que la sangría o el espaciado de las demás sentencias sugieran otra cosa.

   Continuando con el ejemplo, la línea 17 se puede interpretar como: “Si num1 es distinto de num2, ejecuta la sentencia de la línea 18”; mientras que la línea 20: “Si num1 es menor estricto que num2, ejecuta la sentencia de la línea 21”; las líneas 23, 26 y 29 tienen una interpretación análoga.

   Las líneas 15, 18, 21, 24, 27 y 30 deberían ser ya totalmente comprendidas en función de los ejemplos anteriores. Una posible salida del Ejemplo 3.1 se muestra en la siguiente figura:

Una posible salida del Ejemplo 3.1.
 
  Es importante que pruebe y experimente con otros datos, y que se asegure de cubrir todos los casos considerados en las expresiones condicionales de las estructuras de selección if. Esta actividad es conocida como pruebas de caja blanca o transparente, y la validación de todas las sentencias dentro del código de un programa, es una labor relacionada con el concepto de complejidad ciclomática, y aunque la explicación de estos conceptos está fuera de los alcances de este blog, su mención y presentación no.

   Ahora bien, en base al funcionamiento de la estructura de selección if, la explicación realizada, y considerando el caso del intento de división por cero que se mencionó en la entrada Estructuras de control, ¿se le ocurre algo para prevenir dicha indeterminación?

   En este sentido, el Ejemplo 3.2 es una primera propuesta de solución a la indeterminación matemática. Dicha propuesta está dada esencialmente por la línea 15, ya que en ella se realiza la verificación del denominador utilizando la estructura de selección if, y el operador relacional de comparación!=”.

   Si el denominador (den) es distinto de cero (línea 15), entonces es posible realizar la división (línea 16), y presentar el resultado (línea 17).

   Observe que si el denominador es cero, simplemente no se realiza la división y no se presenta ningún tipo de información en la salida estándar lo cual, además de parecer poco cordial e informativo es incorrecto, no desde la perspectiva de la lógica de funcionamiento, sino desde la perspectiva del usuario del programa, ya que no basta con escribir programas funcionales, sino también útiles.

   Por lo anterior, sería bueno proporcionar al usuario algún tipo de notificación acerca de lo que ha ocurrido, para ello, se requiere de algo que permita al programador seleccionar entre un grupo de sentencias u otro en función de una determinada situación, y ese algo es la estructura de control para la selección de sentencias if-else, misma que se describirá en la siguiente entrada. Por ahora, el Ejemplo 3.2 valida y previene una operación de indeterminación matemática, haciéndolo lógicamente funcional.

   Una posible salida para el programa del Ejemplo 3.2 se muestra en la siguiente figura. Al igual que antes, pruebe y experimente con otros datos, genere otras salidas, y verifique qué hace el programa cuando el denominador es cero.

Una posible salida del Ejemplo 3.2.

   Por último, es importante mencionar que en el lenguaje de programación C la división de enteros es entera sin importar que la división no sea exacta, esto quiere decir que en la división de enteros la parte fraccionaria es descartada y sólo se conserva la parte entera. Más adelante se introducirán nuevos tipos de datos (float y double), los cuales proporcionarán un mejor manejo de números fraccionarios.