18 de octubre de 2016

La estructura de control for.

   La estructura de control o ciclo for tiene la siguiente estructura general:

          for ( expresión1; expresión2; expresión3 ) {
              sentencia(s);
          }

   El ciclo for procesa o ejecuta el grupo de sentencia(s) delimitadas por su bloque de manera repetida, mientras la expresión2, al ser evaluada, sea distinta de cero, es decir: expresión2 != 0.

   La llave izquierda “{” delimita el inicio de su bloque, mientras que la llave derecha “}” delimita su final.

   Si se procesan el conjunto de sentencia(s) delimitadas por el bloque del ciclo for, cuando la secuencia de ejecución alcanza el indicador de fin del bloque, la estructura de repetición for modifica el flujo de ejecución secuencial y brinca automáticamente a la evaluación de la expresión3, la cual habitualmente modifica la(s) variable(s) de control; después de esto, el flujo de control se pasa a expresión2, y si expresión2 != 0, se repite el procesamiento de las sentencia(s) delimitadas por el bloque. En caso contrario, se procesa la siguiente sentencia que se encuentre después del indicador de fin de bloque del ciclo for (es un error común de programación terminar por "inercia" una estructura de repetición for con “;”, lo cual no es ningún error respecto a la gramática del lenguaje, por lo que el compilador no identificará nada extraño).

   Cabe mencionar aquí que en un ciclo for cualquiera de las expresiones: expresión1, expresión2, o expresión3, pueden ser vacías. Si expresión2 es vacía, se genera un ciclo infinito.

   La estructura de repetición for es equivalente a la estructura de repetición while en el siguiente sentido:

                  expresión1;
                  while (expresión2) {
                      sentencia(s);
                      expresión3;
                  }

por lo que puede decirse, que cualquier ciclo escrito en una estructura de repetición while puede ser reescrito en la estructura de repetición for y viceversa, de tal forma que es posible mantener la equivalencia lógica y funcional entre una y otra estructura.

   El Ejemplo 3.13 muestra el uso de la estructura de repetición for, el cual genera la misma salida que para el Ejemplo 3.9. Asegúrese de comprender su funcionamiento.

   Considere ahora el Ejemplo 3.14 el cual utiliza una estructura for un poco más elaborada que la anterior para implementar la sumatoria de los números entre 1 y n, dada por la siguiente expresión:
   Observe que es posible inicializar más de una variable en la expresión1 del ciclo for (línea 16): la variable de control i, que sirve para ir generando la serie de números, mientras que la variable sum se utiliza como acumulador. De hecho, es posible tanto inicializar como modificar más de una variable de control en expresión1 y expresión3 respectivamente, y la forma de hacerlo es escribir dichas expresiones como una lista de variables separadas por comas.

   La expresión de la línea 17 del Ejemplo 3.14 puede interpretarse en nuestro lenguaje como: “A la variable sum increméntala en i”, debido a que en C, la expresión:

variable = variable operador expresión;
es equivalente a:

variable operador= expresión;
donde operador es cualquier operador aritmético válido en C, y se le denomina notación compacta. Es muy común escribir este tipo de expresiones usando dicha notación.

   El Ejemplo 3.15 muestra el uso de la estructura de repetición for con dos variables de control i y j, el ciclo puede ser gobernado por ambas variables si el problema a resolver así lo requiere, pero para este ejemplo, sólo se imprimen las variables de control en orden ascendente y descendente respectivamente, como se muestra en la siguiente figura:

Salida del Ejemplo 3.15.
 
    Observe que la expresión1 del ciclo for (línea 11) contiene la inicialización de las dos variables de control separadas por una coma (,). De manera análoga, la expresión3 contiene la modificación, es decir el incremento (i++) y decremento (j--) respectivamente de las variables de control separadas también por una coma.

   Por otro lado, el Ejemplo 3.16 genera una secuencia de quince caracteres (véanse las línea 8, 14 y 15) aleatorios. El programa incluye en la línea 5 la biblioteca estándar stdlib.h, la cual es necesaria para poder utilizar las funciones srand y rand de las líneas 13 y 15 respectivamente.

   La biblioteca time.h de la línea 6 se ha incluido para poder hacer uso de la función time de la línea 13, la cual permite leer la fecha y hora del sistema en donde se ejecuta el programa, y regresa un número de tipo size_t el cual es capaz de almacenar los segundos que han transcurrido desde las cero horas del primero de Enero de 1970, y que es utilizado por la función srand para inicializar la semilla de números aleatorios con un valor distinto en cada ejecución.

   Los números aleatorios son generados por alguna función matemática, y para generarse, se basan en un valor inicial (semilla), si éste valor no cambia, la secuencia de números generados tampoco. Por lo tanto, la función srand es la responsable de cambiar la secuencia de generación de números aleatorios a partir del valor semilla, que para el caso del Ejemplo 3.16, utiliza la hora del sistema cada vez que se ejecuta el programa.

   Ahora bien, la función encargada de generar el número aleatorio a partir de la inicialización que hizo la función srand es la función rand, (línea 15). La función rand genera un número aleatorio entre 0 y RAND_MAX, el cual es un valor dependiente de la implementación de la biblioteca (debido a las diferentes arquitecturas de hardware y software), pero se garantiza que es de al menos 32,767 en cualquier implementación de la biblioteca que se base en el estándar ANSI C.

   Observe que el valor de la función rand es divido por 26, y que el residuo de dicha división es sumado al carácter 'a' (línea 15). Por extraño que parezca (sumarle un número a una letra), tiene sentido al menos en C, y se explica de la siguiente manera:

   Sea n el número que representa el código del carácter 'a' (recuerde que lo que la computadora entiende, procesa y “ve” son sólo números, de hecho el valor del carácter 'a' es traducido por el compilador a su representación numérica, pero para nosotros como seres humanos, es más fácil y claro de entender el símbolo 'a', que el código numérico que lo representa; y aunque se podría poner directamente el código del carácter 'a', el precio a pagar sería la portabilidad a otros sistemas, así como la problemática de los números mágicos discutida con anterioridad), y sea d definido como:

d = rand( ) % 26
y c como:
c = n + d

entonces c estará en el conjunto de las letras:

{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}

   El valor de c representado como carácter, es lo que se imprime en el especificador de formato “%c”, el cual es el especificador de formato en C para los caracteres (char).

   En resumen, el Ejemplo 3.16 genera una secuencia de quince caracteres aleatorios. Antes de avanzar, asegúrese de comprender lo que se ha descrito hasta aquí y por qué el Ejemplo 3.16 genera una salida como la de la siguiente figura. Pruebe con varias ejecuciones, quizá alguna de ellas contenga una palabra medianamente comprensible.

Una posible salida del Ejemplo 3.16.