Unidad 5 Funciones

1. Concepto de Función 
2. Variables
3. Paso de parámetros
4. Recursividad
5. ¿Cómo pasar Parámetros a Funciones?

1. CONCEPTO DE FUNCIÓN
Las funciones son los bloques constructores de C y el lugar donde se da toda la actividad del programa.
La forma general de definición de una función es:
tipo nombre (lista de parámetros)
{
cuerpo de la función
}
El tipo especifica el tipo de valor que devuelve la sentencia return de la función. El valor puede ser cualquier tipo válido; si no se especifica ninguno, se asume un resultado entero.
La lista de parámetros es la lista de nombres de variables separados por comas con sus tipos asociados que reciben los valores de los argumentos cuando se llama a la función.
Una función puede no tener parámetros, en cuyo caso la lista de parámetros está vacía; sin embargo, los paréntesis son necesarios.
Declaración
Cada función debe ser declarada. Su forma general es:tipo nombre_función (lista de tipos (y nombres) de los argumentos); Si una función va usar argumentos, debe declarar variables que acepten los valores de los argumentos. Estas variables se llaman parámetros formales de la función y se comportan como variables locales dentro de la función, creándose al entrar en la función y destruyéndose al salir. La declaración de parámetros aparece después del nombre de la función al definirla.
Los parámetros formales tienen que ser del mismo tipo que los argumentos usados al llamar una función (el compilador no dará error pero los resultados serán inesperados).
Una función es visible para ella misma y otras funciones desde el momento en que se define. Es visible para el propio cuerpo de la función, es decir, la recursividad esta permitida. El código de una función es privado a esa función y sólo se puede acceder a él mediante una llamada a esa función. Las variables definidas dentro de una función son locales (a no ser que las definamos globales) por lo que no conservan su valor de una llamada a otra (excepto si se declaran como static, entonces el compilador no las destruye y almacena su valor para la próxima llamada, aunque la variable tiene limitado el ámbito al interior de la función).
En C, todas las funciones están al mismo nivel, es decir, no se puede definir una función dentro de otra función. Esto es por lo que C no es técnicamente un lenguaje estructurado por bloques.
El código de una función es privado a esa función y sólo se puede acceder a él mediante una llamada a esa función. Las variables definidas dentro de una función son locales (a no ser que las definamos globales) por lo que no conservan su valor de una llamada a otra (excepto si se declaran como static, entonces el compilador no las destruye y almacena su valor para la próxima llamada, aunque la variable tiene limitado el ámbito al interior de la función).
Llamadas a funciones
Las funciones son llamadas para su ejecución desde cualquier parte del código, teniendo en cuenta que antes deben haber sido declaradas (y por supuesto definidas).
La llamada de una función se produce mediante el uso de su nombre en una sentencia, pasando una lista de argumentos que deben coincidir en número y tipo con los especificados en la declaración (en otro caso se produciría una conversión de tipos o resultados inesperados). Llamadas por valor y por referencia En general, se pueden pasar argumentos a las funciones de dos formas, por valor y por referencia.
La llamada por valor copia el valor de un argumento en el parámetro formal de la función. De esta forma, los cambios en los parámetros de la función no afectan a las variables que se usan en la llamada (es la llamada más usual, es decir, en general no se pueden alterar las variables usadas para llamar a la función).
La llamada por referencia copia la dirección del argumento en el parámetro. Dentro de la función se usa la dirección para acceder al argumento usado, significando que los cambios hechos a los parámetros afectan a la variable usada en la llamada.
Es posible simular una llamada por referencia pasando un puntero al argumento, entonces, al pasar la dirección, es posible cambiar el valor de la variable usada en la llamada.

2. VARIABLES
Una variable es un nombre que empieza con una letra y varios caracteres más (el total de caracteres depende de la versión del lenguaje y la computadora que se emplea); se recomienda usar solo letras minúsculas, dígitos y el subguión.
Las variables del lenguaje C están clasificadas en:
Enteras
Reales
De cadena (alfanuméricas)
OTROS DATOS
Variables con índice.
Parámetros asociados a las variables y se emplean para almacenar los valores definidos por constantes de tipo: entero, real y alfanumérico.
VARIABLES ENTERAS
Las variables enteras son aquellas cuyo nombre está mencionado en una declaración de tipo incluida en algún lugar del programa, por ejemplo:
Int a,b,c; unsigned int x,y,z;
También se puede definir la doble precisión para enteras. Por ejemplo:
Long int a,b,c;
VARIABLES REALES
Las variables reales son aquellas cuyo nombre está mencionado en una declaración de tipo incluida en algún lugar del programa, por ejemplo con precisión simple:
float a,b,c; float d=1.0, e=0.5, f=0.0;
y con doble precisión:
double i,j,k; double g=1.567845645,h=-0.54666,f=-1.0;
Las variables alfanuméricas son aquellas cuyo nombre esta mencionado en una declaración de tipo incluida en algún lugar del programa, por ejemplo:
Char g[4]="uno",h[10]="siguiente",index='O';
VARIABLES CON INDICE
Las variables con indice pueden ser de cualquiera de los tipos previamente vistos. Su uso en la ingeniería está relacionado con el manejo de arreglos en una y mas dimensiones (vectores y matrices principalmente). La declaración de ellas se hace como se muestra a continuación:

Tiponombre_de_la_variable [número de elementos];
Todos los arreglos inician con el elemento cero, por consiguiente la declaración que sigue:
Int W[4], z[6][5];
Indica que el vector de valores enteros w[4] cuenta con elementos w[0],w[1],w[2] y w[3], mientras que el siguiente arreglo es una matriz de 6x5, es decir de 30 elementos con valores de tipo entero, con elementos z[0][0],z[0][1]...z[0][4]; z[1][0],z[1][1]...z[1][4];...;z[5][0],z[5][1]...z[5][4].
Observe que en el caso de las variables alfanuméricas se debe considerar el elemento nulo que se agrega automáticamente al final de la cadena.

3. PASO DE PARÁMETROS.
El lenguaje C utiliza el Paso de Parámetros por Valor al pasar argumentos; esto quiere decir que el módulo que es llamado trabaja con una copia de las variables , y por lo tanto cualquier modificación que se quiera hacer a los parámetros no afectará a las variables originales.
Para realizar un Paso de Parámetros por Referencia se hace pasando un apuntador a un argumento, esto implica que se pase la dirección del argumento a la función, entonces es posible cambiar el valor argumento fuera de la función.
#include <stdio.h>
main()
{
      int edad;
           printf (“Dame tu edad \n”);
           scanf (“%d”, &edad);
           imprime (edad) ;
           suma (&edad);
           imprime (edad);
}
  imprime (int b) /* Paso de Parámetros por Valor */
  {
        printf (“Tu edad es %d \n”, b);
        return;
  }
  suma (int *a) /* Paso de Parámetros por Referencia */
    {
       *a=*a+1;
    }

Parámetros asociados a las variables.
Todas las variables tienen asociados tres parámetros muy importantes:
Su nombre, su dirección en memoria, su contenido o valor asignado
Recuerde que cada byte tiene asociada una dirección que permite localizar su contenido en memoria; de igual forma las variables se les asociar esos parámetros.

4. RECURSIVIDAD 
La recursividad es una técnica de programación importante. Se utiliza para realizar una llamada a una función desde la misma función. Como ejemplo útil se puede presentar el cálculo de números factoriales. Él factorial de 0 es, por definición, 1. Los factoriales de números mayores se calculan mediante la multiplicación de 1 * 2 * ..., incrementando el número de 1 en 1 hasta llegar al número para el que se está calculando el factorial.
El siguiente párrafo muestra una función, expresada con palabras, que calcula un factorial.
"Si el número es menor que cero, se rechaza. Si no es un entero, se redondea al siguiente entero. Si el número es cero, su factorial es uno. Si el número es mayor que cero, se multiplica por él factorial del número menor inmediato."
Para calcular el factorial de cualquier número mayor que cero hay que calcular como mínimo el factorial de otro número. La función que se utiliza es la función en la que se encuentra en estos momentos, esta función debe llamarse a sí misma para el número menor inmediato, para poder ejecutarse en el número actual. Esto es un ejemplo de recursividad.
La recursividad y la iteración (ejecución en bucle) están muy relacionadas, cualquier acción que pueda realizarse con la recursividad puede realizarse con iteración y viceversa. Normalmente, un cálculo determinado se prestará a una técnica u otra, sólo necesita elegir el enfoque más natural o con el que se sienta más cómodo.
Claramente, esta técnica puede constituir un modo de meterse en problemas. Es fácil crear una función recursiva que no llegue a devolver nunca un resultado definitivo y no pueda llegar a un punto de finalización. Este tipo de recursividad hace que el sistema ejecute lo que se conoce como bucle "infinito".
Para entender mejor lo que en realidad es el concepto de recursión veamos un poco lo referente a la secuencia de Fibonacci.
Principalmente habría que aclarar que es un ejemplo menos familiar que el del factorial, que consiste en la secuencia de enteros.
0,1,1,2,3,5,8,13,21,34,...,
Cada elemento en esta secuencia es la suma de los precedentes (por ejemplo 0 + 1 = 0, 1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, ...) sean fib(0) = 0, fib (1) = 1 y así sucesivamente, entonces puede definirse la secuencia de Fibonacci mediante la definición recursiva (define un objeto en términos de un caso mas simple de si mismo):
fib (n) = n if n = = 0 or n = = 1
fib (n) = fib (n - 2) + fib (n - 1) if n >= 2
Por ejemplo, para calcular fib (6), puede aplicarse la definición de manera recursiva para obtener:
Fib (6) = fib (4) + fib (5) = fib (2) + fib (3) + fib (5) = fib (0) + fib (1) + fib (3) + fib (5) = 0 + 1 fib (3) + fib (5)
   1. + fib (1) + fib (2) + fib(5) =
   1. + 1 + fib(0) + fib (1) + fib (5) =
   2. + 0 + 1 + fib(5) = 3 + fib (3) + fib (4) =
      3 + 1 + fib (0) + fib (1) + fib (4) =
   3. + fib (1) + fib (2) + fib (4) =
   4. + 0 + 1 + fib (2) + fib (3) = 5 + fib (0) + fib (1) + fib (3) =
   5. + 0 + 1 + fib (1) + fib (2) = 6 + 1 + fib (0) + fib (1) =
   6. + 0 + 1 = 8


Programación Recursiva:

Es mucho más difícil desarrollar una solución recursiva en C para resolver un problema especifico cuando no se tiene un algoritmo. No es solo el programa sino las definiciones originales y los algoritmos los que deben desarrollarse. En general, cuando encaramos la tarea de escribir un programa para resolver un problema no hay razón para buscar una solución recursiva. La mayoría de los problemas pueden resolverse de una manera directa usando métodos no recursivos. Sin embargo, otros pueden resolverse de una manera más lógica y elegante mediante la recursión.
Volviendo a examinar la función factorial. El factor es, probablemente, un ejemplo fundamental de un problema que no debe resolverse de manera recursiva, dado que su solución iterativa es directa y simple. Sin embargo, examinaremos los elementos que permiten dar una solución recursiva. Antes que nada, puede reconocerse un gran número de casos distintos que se deben resolver. Es decir, quiere escribirse un programa para calcular 0!, 1!, 2! Y así sucesivamente. Puede identificarse un caso "trivial" para el cual la solución no recursiva pueda obtenerse en forma directa. Es el caso de 0!, que se define como 1. El siguiente paso es encontrar un método para resolver un caso "complejo" en términos de uno más "simple", lo cual permite la reducción de un problema complejo a uno más simple. La transformación del caso complejo al simple resultaría al final en el caso trivial. Esto significaría que el caso complejo se define, en lo fundamental, en términos del más simple.
Examinaremos que significa lo anterior cuando se aplica la función factorial. 4! Es un caso más complejo que 3!. La transformación que se aplica al número a para obtener 3 es sencillamente restar 1. Si restamos 1 de 4 de manera sucesiva llegamos a 0, que es el caso trivial. Así, si se puede definir 4! en términos de 3! y, en general, n! en términos de (n – 1)!, se podrá calcular 4! mediante la definición de n! en términos de (n – 1)! al trabajar, primero hasta llegar a 0! y luego al regresar a 4!. En el caso de la función factorial se tiene una definición de ese tipo, dado que:
n! = n * (n – 1)!
Así, 4! = 4 * 3! = 4 * 3 * 2! = 4 * 3 * 2 * 1! = 4 * 3 * 2 * 1 * 0! = 4 * 3 * 2] * ] = 24
Estos son los ingredientes esenciales de una rutina recursiva: poder definir un caso "complejo" en términos de uno más "simple" y tener un caso "trivial" (no recursivo) que pueda resolverse de manera directa. Al hacerlo, puede desarrollarse una solución si se supone que se ha resuelto el caso más simple. La versión C de la función factorial supone que está definido (n –1)! y usa esa cantidad al calcular n!.
Otra forma de aplicar estas ideas a otros ejemplos antes explicados. En la definición de a * b, es trivial el caso de b = 1, pues a * b es igual a a. En general, a + b puede definirse en términos de a * (b – 1) mediante la definición a * b = a * (b – 1) + a. De nuevo, el caso complejo se transforma en un caso más simple al restar 1, lo que lleva, al final, al caso trivial de b = 1. Aquí la recursión se basa únicamente en el segundo parámetro, b.
Con respecto al ejemplo de la función de Fibonacci, se definieron dos casos triviales: fib(0) = 0 y fib(1) = 1. Un caso complejo fib(n) se reduce entonces a dos más simples: fib(n –1) y fib(n –2). Esto se debe a la definición de fib(n) como fib(n –1) + fib(n – 2), donde se requiere de dos casos triviales definidos de manera directa. Fib(1) no puede definirse como fib(0) + fib(-1) porque la función de Fibonacci no está definida para números negativos.

5. ¿CÓMO PASAR PARÁMETROS A FUNCIONES?

Una función puede recibir tantos parámetros como queramos y para expresarlo se colocan los nombres de los parámetros separados por comas, dentro de los paréntesis. Veamos rápidamente la sintaxis para que la función de antes, pero hecha para que reciba dos parámetros, el primero el nombre al que saludar y el segundo el color del texto.

function escribirBienvenida(nombre,colorTexto){
    document.write("<FONT color='" + colorTexto + "'>")
    document.write("<H1>Hola " + nombre + "</H1>")
    document.write("</FONT>")
}

Llamaríamos a la función con esta sintaxis. Entre los paréntesis colocaremos los valores de los parámetros.

var miNombre = "Pepe"
var miColor = "red"
escribirBienvenida(miNombre,miColor)

He colocado entre los paréntesis dos variables en lugar de dos textos entrecomillados. Cuando colocamos variables entre los parámetros en realidad lo que estamos pasando a la función son los valores que contienen las variables y no las mismas variables. 
Los parámetros se pasan por valor.
Al hilo del uso de parámetros en nuestros programas Javascript, tenemos que saber que los parámetros de las funciones se pasan por valor. Esto quiere decir que estamos pasando valores y no variables. En la práctica, aunque modifiquemos un parámetro en una función, la variable original que habíamos pasado no cambiará su valor. Se puede ver fácilmente con un ejemplo.

function pasoPorValor(miParametro){
    miParametro = 32
    document.write("he cambiado el valor a 32")
}
var miVariable = 5
pasoPorValor(miVariable)
document.write ("el valor de la variable es: " + miVariable)

En el ejemplo tenemos una función que recibe un parámetro y que modifica el valor del parámetro asignándole el valor 32. También tenemos una variable, que inicializamos a 5 y posteriormente llamamos a la función pasándole esta variable como parámetro. Como dentro de la función modificamos el valor del parámetro podría pasar que la variable original cambiase de valor, pero como los parámetros no modifican el valor original de las variables, ésta no cambia de valor.
De este modo, una vez ejecutada la función, al imprimir en pantalla el valor de miVariable se imprimirá el número 5, que es el valor original de la variable, en lugar de 32 que era el valor con el que habíamos actualizado el parámetro.