Programación en C/Uso de Funciones

De Wikilibros, la colección de libros de texto de contenido libre.

← Instrucciones de control Uso de Funciones Vectores →


Contenido

[editar] Funciones

Como vimos anteriormente C tiene como bloque básico la función. main() es una función, printf() otra, y hay muchas más funciones predefinidas, pero nosotros mismos también podemos definir las nuestras propias. De hecho, es fundamental hacerlo.

Podemos definir una función cualquiera de la misma manera en que definimos la función main(). Basta con poner su tipo, su nombre, sus argumentos entre paréntesis y luego, entre llaves, su código:

/* Inclusión de archivos */
#include <stdio.h>
 
void holamundo(void) /*Función donde se ejecuta la lógica del programa*/
{
 	printf("Hola Mundo\n"); /*imprime la cadena*/
	return; /*sale de la función*/
}
 
int main(void) /*Función principal del programa*/
{
	holamundo(); /*llamada a la función que lleva el peso*/
	return 0; /*sale del programa: correcto*/
}

Este código es en todo equivalente al "Hola Mundo" original, sólo que nos muestra cómo escribir y cómo utilizar una función. Y además nos muestra un principio de buena programación: meter las sentencias que "hacen el trabajo" en otras funciones específicas para sacarlas de main(), dejando en ésta tan sólo un guión general de lo que hace el programa, no las órdenes específicas. De esta manera se facilita la comprensión del programa, y por tanto el futuro trabajo de modificarlo.

De la misma manera que tenemos que declarar una variable antes de utilizarla, no es indiferente el orden en que se sitúen las diferentes funciones en el fichero: las funciones deben declararse antes de ser llamadas.

Igualmente vemos que, para una función void, la sentencia de control return no puede llamarse como pseudofunción, porque en dicho caso la función void (en nuestro caso holamundo()) devolvería un valor, cosa que su definición no permite.

Las funciones tambien permiten recibir tipos de datos, asi pues las funciones nos sirven para hacer de un gran problema pequeñas partes de un problema osea dividir un gran problea en diferentes problemas más pequeños. Asi que las funciones tambien pueden retornar un tipo de dato que hemos definido dentro de la misma.

Asi que si definimos una funcion para sumar dos numeros seria de la siguiente manera:

/*
 *  suma.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
int sumar(int numero1, int numero2); /* prototipo de la función */
 
int main(void)
{
	int suma; /* definimos una variable*/
 
	suma = sumar(5, 3);
	/* la variable obtiene el valor retornado de sumar
	 * puede verse que entre los paréntesis se mandan los valores
	 * de los numeros que se desean sumar en este caso 5 y 3
	 * pueden haberse declarados estos dos números en otras variables
	 * int dato = 4, valor = 3;
	 * suma = sumar(dato, valor);
	 */
 
	/* imprimimos la suma de los dos números */
	printf("La suma es: %d ", suma);
 
	return 0;
}
 
int sumar(int numero1, int numero2)
{
	int retsuma; /* creamos la variable a retornar*/
 
	retsuma = numero1 + numero2; /* asignamos esa varia la suma de número 1 y 2*/
 
	return retsuma; /* retornamos la suma de los números */
}


[editar] Paso de Parámetros

Las funciones pueden recibir datos como lo hemos observado, pero existen dos formas importantes de enviar los datos hacia una función por valor y por referencia, con las cuales observarse que son muy diferentes y que una puede ser muy diferente de la otra, haciendo modificaciones en nuestro programa.

[editar] Por Valor

El paso por valor envía una copia de los parámetros a la función por lo tanto los cambios que se hagan en ella no son tomados en cuenta dentro de la función main(). Ejemplo:

/*
 * por_valor.c
 * 
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 * 
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
void sumar_valor(int numero); /* prototipo de la función */
 
int main(void)
{
	int numero = 57; /* definimos numero con valor de 57*/
 
	sumar_valor(numero); /* enviamos numero a la función */
 
	printf("Valor de numero dentro de main() es: %d\n", numero);
	/* podemos notar que el valor de numero se modifica
	 * sólo dentro de la función sumar_valor pero en la principal
	 * número sigue valiendo 57 
	 */
 
	return 0;
}
 
void sumar_valor(int numero)
{
	numero++; /* le sumamos 1 al numero */
 
	/* el valor de número recibido se aumenta en 1
	 * y se modifica dentro de la función sumar_valor()
	 */
	printf("Valor de numero dentro sumar_valor() es: %d\n", numero);
 
	return;
}

[editar] Por Referencia

El paso por referencia se hace utilizando apuntadores. Se envía la dirección de memoria de la variable, por lo tanto los cambios que haga la función si afectan el valor de la variable. Ejemplo:

/*
 * por_referencia.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
void sumar_referencia(int *numero); /* prototipo de la función */
 
 
int main(void)
{
	int numero = 57; /* definimos numero con valor de 57*/
 
	isumar_referencia(&numero); /* enviamos numero a la función */
 
	printf("\nValor de numero dentro de main() es: %d ", numero);
	/* podemos notar que el valor de numero se modifica
	 * y que ahora dentro de main() también se ha modificado
	 * aunque la función no haya retornado ningún valor.
	 */
 
	return 0;
}
 
void sumar_referencia(int *numero)
{
	*numero += 1; /* le sumamos 1 al numero */
 
	/* el valor de numero recibido se aumenta en 1
	 * y se modifica dentro de la función
	 */
	printf("\nValor de numero dentro sumar_referencia() es: %d", *numero);
 
	return;
}

[editar] Variables Locales y Globales

Ademas de pasar valores a una funcion, tambien se pueden declarar tipos de datos dentro de las funciones, estos tipos de datos declarados dentro de una funcion solo son accesibles dentro de esta misma funcion y se les conocen como variables locales, asi pues podemos definir los mismos nombres de variables en diferentes funciones, ya que estas variables solo son accesibles dentro de esas funciones. Ejemplo:

/*
 * locales.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
void funcion1()
{
	int dato = 53; /* definimos dato en 53*/
	char num1 = 'a'; /* num1 vale a */
 
	/* imprimimos */
	printf("Funcion1, dato=%d, num1=%c\n", dato, num1);
 
	return;
}
 
void funcion2()
{
	int dato = 25; /* definimos dato en 25*/
	char num2 = 'z'; /* num2 vale z*/
 
	/* imprimimos */
	printf("Funcion2, dato=%d, num2=%c\n", dato, num2);
 
	return;
}
 
int main(void)
{
	funcion1(); /* llamamos a funcion1() */
 
	funcion2(); /* llamamos a funcion2() */
 
	return 0;
}

En este caso la variable dato, esta definida dentro de cada una de las funciones y son totalmente distinta una de otra y no se puede utilizar fuera de esta, asi pues num2 no puede ser utilizada por la funcion1() y num1 tampoco puede ser utilizada por funcion2().

Existen pues variables que se definen fuera de la funcion principal main() y fuera de cualquier otra funcion creada por nosotros, estas variables se les conoce con el nombre de Variables Globales ya que se pueden utilizar dentro de main() y dentro de cualquier funcion creada por nosotros. Ejemplo:

/*
 * global.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
int variable_global = 99; /* inicializamos la variable global */
 
void funcion();
 
int main(void)
{
	/* imprimimos el valor*/
	printf("main(), acceso a variable_global %d\n", variable_global);
 
	/* llamamos a la función */
	funcion();
 
	return 0;
}
 
void funcion()
{
	/* imprimimos el valor*/
	printf("funcion(), acceso a variable_global %d\n", variable_global);
 
	return;
}

[editar] Funciones Recursivas

La recursividad (recursión) es la propiedad de una función por la cual dicha función se llama a sí misma directa o indirectamente. La recursión indirecta implica utilizar más de una función.

Se puede considerar la recursividad como como una alternativa a la iteración. La recursión permite especificar soluciones naturales, sencillas, que serian, en caso contrario, difíciles de resolver. Toda función recursiva debe contemplar un caso base o condición de salida, para terminar, o la recursividad no puede terminar nunca.

Una función recursiva podría definirse así:

funcion_recursiva( /* parámetros recibidos por la función */ )
{
	/* Código */
	funcion_recursiva( ); /* llamada a la función misma */
	/* Código */
}

Uno de los ejemplos más representativos en la recursividad es el factorial de un numero ( n! ):

 n!=\prod_{k=1}^n k \qquad \forall n \in \mathbb{N}\!

la definición de recursividad del factorial es:

 n! = \begin{cases}
1 & \text{ Si } n = 0 \\
n (n-1)! & \text{ Si } n > 0 \\
\end{cases}
\qquad \forall n \in \mathbb{N}.

En esta definición, n = 0, es nuestro caso base, que le da fin a la recursividad.

Entonces nuestro programa que calcula el factorial es:

/*
 *factorial.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
long factorial(int n)
{
	if (n == 0) /* caso base */
		return 1; /* como 0! = 1, se retorna 1*/
	else
		return n * factorial (n - 1); /* llamada a esta misma función */
}
 
int main(void)
{
	/* en este caso se llama a la función y se imprime directamente*/
	printf("%ld ", factorial(5));
 
	return 0;
}

También existen otros tipos de funciones recursivas como lo es el producto de dos números. El producto de a \times b, donde a y b son números enteros positivos seria:

Solución iterativa:

 a \times b = \begin{matrix}\underbrace{a+a+\cdots+a} \\ \ b\ veces \end{matrix} = \sum_{i=1}^b a

Solución recursiva:

 a \times b = \begin{cases}
0 & \text{ Si } b = 0 \\
a + a \times (b-1) & \text{ Si } b > 0 \\
\end{cases}

Así pues 7 \times 3 es:

 7 \times 3 = 7 + 7 \times 2 = 7 + 7 + 7 \times 1 = 7 + 7 + 7 + 0 =
21

Podemos ver que la multiplicación de dos números a, b se puede transformar en otro problema más pequeño multiplicar a por (b-1), el caso base se produce cuando b = 0 y el producto es 0. Ejemplo:

/*
 * producto.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
int producto(int a, int b)
{
	if (b == 0) /* caso base */
		return 0; /* como b = 0, se retorna 0*/
	else
		return a + producto (a, b - 1); /* llamada a esta misma función */
}
 
int main(void)
{
	/* en este caso se llama a la función y se imprime directamente*/
	printf("%i ", producto( 7, 3));
 
	return 0;
}

[editar] Recursividad indirecta o recursión mutua

Esta se produce cuando una función llama a otra, que esta a su vez terminará llamando de nuevo a la primera función. El siguiente programa visualiza el alfabeto utilizando recursión indirecta o mutua:

/*
 * elalfabeto.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
void funcionA(char c); /* se declara el prototipo de la función para que el llamado */
void funcionB(char c); /* a la misma en la función no sea implícita */
 
int main(void)
{
 
	funcionA('z'); /* llamado a funcionA */
 
	return 0;
}
 
void funcionA(char c)
{
	if (c > 'a') /* caso base mientras c no sea menor que A */
		funcionB(c); /* llamado a la funcionB */
 
	printf("%c ", c); /* imprimimos el valor de c */
}
 
void funcionB(char c)
{
	funcionA(--c); /* llamado a la funcionA decrementando el valor de 'z' */
}

[editar] Recursión versus Iteración

Tanto la iteración como la recursión se basan en estructura de control: la iteración utiliza una estructura repetitiva y la recursión una estructura de selección. La iteración utiliza explícitamente una estructura repetitiva mientras que la recursión consigue la repetición mediante llamadas repetitivas a funciones.

La iteración termina si la condición del bucle no se cumple, mientras que la recursión termina cuando se reconoce un caso base.

La recursión puede presentar desventajas ante la iteración ya que se invoca repetidas veces al mecanismo de llamada de funciones y se necesita un tiempo mayor para realizar cada llamada.

La razón por la cual se puede elegir u optar por usar recursividad es que existen muchos problemas complejos que poseen naturaleza recursiva y, en consecuencia, son mas fáciles de implementar.

[editar] Ejemplo Iterativo

/*
 * iterativo.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
long factorial(int numero);
 
int main(int argc, char** argv)
{
	int contador = 0;
 
	/* calcula el factorial de 0 a 10 */
	for ( contador = 0; contador <= 10; contador++ )
		printf("%d! = %ld\n", contador, factorial( contador ));
 
	return 0;
}
 
/* funcion factorial iterativa */
long factorial( int numero )
{
	long resultado = 1;
	int i = 0;
 
	/* declaracion de la función factorial iterativa */
	for ( i = numero; i >= 1; i-- )
		resultado *= i;
 
	return resultado;
}

[editar] Ejemplo Recursivo

/*
 * recursivo.c
 *
 * Julio César Brizuela <brizuelaalvarado@gmail.com> 2009
 *
 * para el wikilibro "Programación en C"
 * bajo licencia FDL, adaptado del Dominio Público
 */
 
#include <stdio.h>
 
long factorial(int numero);
 
int main(int argc, char** argv)
{
	int contador = 0;
 
	/* calcula el factorial de 0 a 10 */
	for ( contador = 0; contador <= 10; contador++ )
		printf("%d! = %ld\n", contador, factorial( contador ));
 
	return 0;
}
 
/* función factorial recursiva */
long factorial( int numero )
{                                               
	if ( numero <= 0 ) /* caso base */
		return 1; /* casos bases: 0! = 1 y 1! = 1 */
	else /* llamada recursiva */
		return numero * factorial( numero - 1 ); /* llamada a la función factorial */
}


← Instrucciones de control Uso de Funciones Vectores →
Herramientas personales