28 de octubre de 2019

Estructura para las funciones en C.

   La estructura general de la definición de una función en el lenguaje de programación C, es la siguiente:

tipo_de_dato_de_retorno   nombre_de_función (lista_de_parámetros) {

       tipo_de_dato variables_locales;

           sentencia1; 
                 .
                 .
                 .

           sentenciaN;

           return variable;
}


donde:
  • tipo_de_dato_de_retorno: es el tipo de dato del valor que la función regresará, y debe ser congruente con el de variable.
  • nombre_de_función: es un identificador válido en C para nombrar a la función. A partir de él se harán los llamados respectivos. Se recomienda un nombre representativo que dé idea de la labor que realiza la función.
  • lista_de_parámetros: es una lista de variables separada por comas ",”, cada una con su propio identificador y tipo de dato; es el mecanismo de comunicación de la función con el exterior, su interfaz. Esta lista, junto con las variables_locales, constituyen las variables locales a la función.
  • tipo_de_dato: es alguno de los tipos de datos del lenguaje de programación C.
  • variables_locales: es una lista de variables locales a la función, mismas que serán utilizadas por la función en el grupo de sentencia(s).
  • sentencias: son el grupo de sentencias que representan, definen, describen y detallan la funcionalidad o utilidad de la función. Las sentencias en conjunto con las variables locales, conforman el algoritmo que encapsula la función.
  • return: es una palabra reservada, y se utiliza para regresar al invocador de la función el valor determinado por variable.

   Al trabajar con funciones de biblioteca, la directiva #include es sumamente importante ya que incluye, entre otras cosas, los prototipos de función de las funciones de biblioteca que se utilizan en el programa que la contiene.

   Por otro lado, el llamado de función ocurre cuando se escribe el nombre de la función que se va a utilizar, pero el código fuente (la definición de la función) no es accesible debido a que se encuentra en formato binario, listo para ser asociado y vinculado al programa que lo necesite durante el proceso de compilación y vinculación. El llamado de función sería el equivalente a presionar un botón de una calculadora para obtener un cálculo, como por ejemplo, obtener la raíz cuadrada de un número.



21 de octubre de 2019

Repetición controlada por centinela.

   No en todos los problemas es posible conocer de manera anticipada cuantas veces se repetirá un grupo de sentencias. Es en este tipo de situaciones cuando tenemos el tipo de repetición controlada por centinela.

   El centinela es un valor que se utiliza para determinar la continuidad o no del ciclo a partir de la evaluación de la expresión condicional del mismo, es decir, el centinela determina si el grupo de sentencias asociadas se procesarán o no nuevamente. Por lo general, el valor del centinela forma parte de la expresión condicional de la estructura de control de repetición, y puede estar dado de manera explícita o implícita.

    Considere el ejercicio de la división y su solución del Ejemplo 3.12, ahí el centinela está implícito, debido a que la descripción del problema no contempla la designación del cero como centinela, sino que la naturaleza misma del problema lo requiere de esa manera ante la posible indeterminación de la división.

   En otros casos, el centinela se describe de manera explícita, como en los siguientes ejemplos:
  • Determinar el promedio de una lista de calificaciones, en donde cada calificación será introducida desde el teclado una a la vez. El fin de la lista de calificaciones sera indicado con -1, debido a que la lista es variable.
  • Determinar la suma de los números enteros proporcionados desde el teclado, hasta que el número proporcionado sea cero.
  • Dada una lista de números enteros positivos, determine el mayor y el menor de ellos, la lista termina al proporcionar cualquier número negativo.
   Aunque la repetición controlada por centinela es menos frecuente, no es menos necesaria ni menos importante que la repetición controlada por contador, de ahí la importancia de presentarla, conocerla y dominarle como parte de su repertorio como programador y de las técnicas utilizadas en la resolución de problemas.

   Considere el Ejemplo 3.19, el cual resuelve el mismo problema que el Ejemplo 3.18 pero utilizando un enfoque diferente: el de la repetición controlada por centinela.

   Note que en la repetición controlada por centinela, podría ser que el primer dato procesado fuera el centinela, por lo que no habría calificaciones a promediar, lo cual no es posible de hacer en la repetición controlada por contador, en donde se está obligado a proporcionar las N (diez por ejemplo) calificaciones; sin embargo, es posible simular el mismo tipo de ejecución, tal y como se muestra en la siguiente figura:

Una posible salida para el Ejemplo 3.19.
 
   Compare los ejemplos y sus correspondientes salidas, y asegúrese de entenderlos.

Arreglos de apuntadores a funciones.

   En diferentes tipos de programas y aplicaciones es frecuente encontrar menús de opciones para seleccionar una determinada acción u operación a realizar.

   Cuando muchas o todas las opciones presentadas en un menú comparten características similares, una excelente opción, aunque no la única, es implementar dichas opciones a través de un arreglo de apuntadores a función.

   En el Ejemplo 4.3 se desarrolló una calculadora con las operaciones aritméticas básicas de suma, resta, multiplicación y división. En esta entrada se retomará dicho ejemplo para reescribirlo utilizando un arreglo de apuntadores a funciones.

   El Ejemplo 7.13 muestra que las cuatro funciones de suma, resta, multiplica y divide comparten un patrón común: todas reciben dos argumentos de tipo float y regresan un valor de tipo float.

   El patrón identificado se aprovecha en la línea 15, la cual declara el arreglo funciones de cuatro apuntadores a funciones que reciben dos argumentos de  tipo float y regresan un valor de tipo float. El arreglo es inicializado en la declaración con una lista de identificadores: suma, resta, multiplica y divide.

   El uso del arreglo de apuntadores funciones se presenta en la línea 29, en donde el valor de la variable op se utiliza como índice para invocar a la función correspondiente que realizará la operación seleccionada en base al menú de opciones (líneas 37-51).

   En este sentido, si op tiene el valor tres por ejemplo, la expresión:

( * funciones[op - 1]) ( a, b )

se transforma en la expresión:

multiplica(a, b)

debido a que el identificador que se encuentra en la posición dos (op - 1) del arreglo de apuntadores a funciones funciones, es precisamente multiplica. La resolución de los otros identificadores ocurre de manera análoga.

   El llamado a la función a invocar se resuelve en tiempo de ejecución, ya que el llamado a través del arreglo de apuntadores a funciones de la línea 29 es un llamado implícito.

   Finalmente, la función menu indica con void que no recibirá ningún tipo de argumento. Todos los demás detalles del programa de ejemplo ya deberían resultarle familiares al lector. Una posible salida para el Ejemplo 7.13 se muestra en la siguiente figura:

Una posible salida del Ejemplo 7.13.
   Cabe mencionar por último que la forma de utilizar los arreglos de apuntadores a funciones mostrada en el Ejemplo 7.13 no es su única posibilidad de uso, sino que es una de tantas en el amplio abanico de opciones en la programación estructurada; en este sentido, la limitante respecto al uso de apuntadores a funciones estará en general más en función de la imaginación y capacidad del programador, que de las múltiples posibilidades de su uso y aplicación.