Declaración de funciones

Una función en un lenguaje de programación sigue la idea de una función matemática, la cual a partir de un elemento de entrada, devuelve como máximo un valor de salida, a menudo después de realizar unos cálculos (aplicando una fórmula matemática). En nuestro caso, una función puede verse como una “caja negra” que a partir de unas entradas (no necesariamente una), a las que llamaremos parámetros, nos devuelve un valor. Las instrucciones internas de la función (lo que llamaremos cuerpo de la función) sólo las debe conocer el implementador de esta función, pero no los programadores que después lo utilicen. Así, estos últimos verán la función “f” de esta forma:

Por ejemplo, vamos a escribir una función que calcule el factorial de un número entero positivo. Como entrada tiene un número entero (int), y el valor que se devuelve es otro entero (que como que puede ser muy grande le declararemos como long int).

Este código define la función factorial. Veamos que tiene dos partes, la cabecera y el cuerpo. En la cabecera es donde se definen el nombre de la función, los parámetros (y su tipo), así como el tipo del valor que se devolverá. Por lo general, sigue la siguiente forma:

tipo_retornado nombre_función(tipo1 param1, tipo2 param2,...)

Como hemos indicado antes, ésta es la parte que los programadores que utilicen la función deben conocer. En cambio, el cuerpo de la función contiene todas las instrucciones a ejecutar. En concreto, siempre debemos indicar con return el valor que la función devuelve (y que debe coincidir con el tipo declarado en la cabecera). Cuando la función encuentra una instrucción de retorno, termina su ejecución y devuelve el valor correspondiente. Una función puede tener más de una instrucción de retorno, aunque suele ser más claro que sólo exista una al final de la función. Para poder utilizar esta función factorial en nuestro programa, debemos incluir su definición en el archivo. Veamos un ejemplo de un programa que calcula el factorial de una variable x (la cual hemos inicializado a 5):

#include <stdio.h>
long int factorial(int n) {
   int y;
   long int f = 1;
   for (i = n;i >= 2;i--) {
      f = f * i;
   }
   return f;
}

void main() {
   int x = 5;
   long int nada;
   nada = factorial(x); Llamamiento a la función factorial
   printf("%d\n",nada);
}

En la línea res=factorial(x); se hace lo que se llama la llamada a la función factorial, es decir, se ejecuta la función (las instrucciones del cuerpo) sustituyendo el parámetro n de factorial por el valor de la variable x (que es 5). Esto nos devuelve el valor 120, que es lo que se asigna a nada. Véase que al llegar a esta línea, el programa se pone a ejecutar la función y no continúa ejecutando el main hasta que no hemos terminado la función factorial devolviendo un valor. Internamente, cuando se hace la llamada a la función se carga el espacio de memoria propio de la función factorial. El valor del parámetro en la llamada (x en el ejemplo que tiene el valor 5) se copia en el espacio del parámetro de la función factorial (n en el ejemplo). A esta acción de la copia del valor no se le llama parámetro por valor. También, para distinguir el parámetro de la llamada del parámetro definido en la función, al primero se le llama parámetro real (o parámetro de llamada) y en el segundo parámetro formal. Nótese que aunque podrían coincidir, el nombre de la variable del parámetro de llamada (x en el ejemplo) y del parámetro formal (n en el ejemplo) no tienen por qué ser iguales, como de hecho ocurre en nuestro ejemplo. Si ni hubiera más de un parámetro, se asignan por orden el nombre no tiene nada que ver!). Veamos un ejemplo:

int mayor(int a, int b) {
   if (a >= b) return 1;
   else return 0;
}

main() {
   int a = 5, b = 3, c;
   c = mayor(b, a);
...
}

Véase que cuando se llama a mayor(b, a) se hace la copia del valor de b (3) en el parámetro a y del valor de a (5) en el parámetro b. Así que dentro de la función mayor, a vale 3 y b vale 5 y por tanto se devuelve el valor 0 (porque a<b).

Nótese que además de los parámetros, en la definición del cuerpo de la función hemos declarado unas variables (e y f en el ejemplo del factorial). Éstas reciben el nombre de variables locales y sólo pueden ser utilizadas dentro del ámbito de la función donde están declaradas (factorial en ejemplo), pero no se pueden utilizar fuera, por ejemplo dentro del main. Se dice que y yf no son visibles en el main (sólo son visibles en factorial). Las variables locales se cargarán en la memoria cuando se llama la función (dentro del bloque de memoria propio de la función). En el apartado de visibilidad veremos esto con mayor detalle.

Una restricción del lenguaje C, que no tienen otros como Pascal, es que no pueden definirse funciones dentro de otras funciones. Pascal, al igual que se declaran variables locales sólo accesibles por una función, también se pueden definir sub-funciones, sólo accesibles dentro de la función donde están definidas, teniendo así una jerarquía de funciones a distintos niveles. En C sólo existe un único nivel de funciones.

El programa principal debe “conocer” qué significa factorial(x), si no daría un error de compilación. Por eso es necesario poner la definición de la función previamente. Así el compilador puede comprobar si el número de parámetros y su tipo es el correcto y si, en el nuestro ejemplo, se puede asignar el valor devuelto (un long int) a la variable nada (también de tipo long int). Si por alguna razón debemos declarar la función después de donde está llamada (después del main en el ejemplo), es necesario declarar antes la cabecera, para que el compilador pueda realizar las comprobaciones correspondientes. Esto es lo que se llama el prototipo de la función. En realidad en C esta declaración del prototipo no es obligatoria pero sí aconsejable puesto que facilita la labor del compilador. Sería así:

#include <stdio.h>
long int factorial(int n);

main() {
  int x=5; long int nada;
  nada=factorial(x);
  printf("%d\n",nada);
}

long int factorial(int n) {
  int y;
  long int f = 1;
  for (i = n;i >= 2;i--) {
    f=f*i;
  }
  return f;
}

Procedimientos

Un procedimiento es un subprograma que ejecuta un proceso específico sin devolver ningún valor determinado. No hay ningún valor asociado al nombre del procedimiento, por lo que no se puede realizar servir éste dentro de una expresión. No todos los lenguajes disponen de procedimientos como tales. Por ejemplo en C no hay y la diferencia entre una función y un procedimiento se pone de manifiesto sólo en el tipo de datos que devuelve. Las funciones que actúan como tales devuelven un tipo concreto, mientras las que no devuelven nada, y por tanto hacen de procedimientos devuelven un tipo void.

Pin It