Este documento presenta un resumen de las funciones en lenguaje C. Explica conceptos como la declaración y definición de funciones, el paso de parámetros, el ámbito de las variables, el uso de la memoria RAM, funciones recursivas, funciones inline, la función main(), y más. El documento parece ser parte de una presentación o apuntes sobre programación funcional en C, enfocándose en el uso correcto de funciones para dividir un problema grande en problemas más pequeños.
00/01 - Introduccion al curso y a la estadística descriptiva
05 - Funciones en lenguaje C
1. 1
05 – Funciones en lenguaje C
Diego Andrés Alvarez Marín
Profesor Asociado
Universidad Nacional de Colombia
Sede Manizales
2. 2
Temario
Programación funcional
Declaración (prototipos) y
definición de funciones
return;
Ambito de las variables
Variables auto
Variables static
Uso de la memoria RAM
Llamada a función (paso de
parámetros por valor y por
referencia)
Funciones recursivas
Funciones inline
Funciones anidadas
La función main()
Las funciones getopt() y
getopt_long()
La función exit()
Funciones variádicas
Llamado de funciones usando
punteros a funciones
3. 3
Divide y vencerás:
la programación funcional
Divida un problema grande en muchos problemas
pequeños
http://en.wikipedia.org/wiki/Comparison_of_programming_paradigms
5. 5
Declaración de funciones o
prototipos de funciones
La declaración/Los prototipos de funciones son
opcionales, pero se recomienda fuertemente, para
evitar alertas (warnings) en la compilación. Estas
se deben poner antes del primer uso de la función.
tipo_que_retorna nombre_de_funcion(lista_de_parametros);
Si la función no retorna nada entonces el
tipo_que_retorna debe ser void
nombre_de_funcion: puede ser cualquier
identificador válido
lista_de_parametros: pueden ser cero (void) o
más parámetros separados por comas.
6. 6
Declaración de funciones o
prototipos de funciones
Se deben colocar antes del main(), con el objeto que
el programa sepa que las funciones existen. De
hecho los archivos *.h están llenos de prototipos de
funciones, y las funciones como tal están en otros
archivos *.c.
Ejemplo de prototipo:
double area_trapecio(double B, double b, double h);
o simplemente:
double area_trapecio(double, double, double);
7. 7
Declaración de funciones
Ejemplos:
Los nombres de las variables en la declaración no
necesitan ser iguales a aquellos en la definición
(aunque se aconseja por orden).
Cuando se crean librerías, las declaraciones se
ponen en un archivo .h y se llaman utilizando un
#include
9. 9
Definición de funciones
La declaración de una función debe ser de la
siguiente forma:
tipo_que_retorna nombre_de_funcion(lista_de_parametros)
{
cuerpo de la función
}
tipo_que_retorna y nombre_de_funcion deben ser
los mismos especificados en el prototipo.
10. return
Termina la ejecución de una función y retorna el
control a la función que la llamó
return valor_a_retornar;
valor_a_retornar es opcional. Si el tipo de
retorno de la función es void, entonces no se
puede retornar una expresión, pero si se puede
usar el return solo.
Es una mala práctica de programación no
retornar un valor en funciones que se dijo que se
iba a retornar un valor.
12. 12
Ambito de variables
(variable scope)
El ámbito de una variable determina el rango del código
sobre el cual dicha variable existe y por lo tanto puede
ser utilizada.
Esto sirve para que se pueda volver a definir una
variable con un mismo nombre en diferentes partes del
programa sin que hayan conflictos entre ellos.
Se recomienda que el ámbito de una variable sea tan
pequeño como sea posible, de modo que se reduzca el
número de variables que se tengan que tener presentes
cuando se programe, lo cual redunda en menores
errores de programación.
13. 13
Ambito de variables
(variable scope)
Si una variable es declarada dentro de un bloque
(método/función/procedimiento), ésta será válida solo
dentro de ese bloque y se destruirá al terminar el bloque.
Adicionalmente, la variable no podrá verse ni usarse
fuera del bloque (en el exterior del bloque).
La variable dentro del bloque es una variable local
(variable auto) y solo tiene alcance dentro del bloque que
se creó y sus bloques hijos, pero no en bloques
hermanos ni padres.
Una variable definida fuera de cualquier bloque es una
variable global y cualquier bloque puede acceder a ella y
modificarla.
14.
15. Ambito de las variables
Las variables se dividen en variables globales y
locales.
Las variables locales sólo existen en el bloque en
el cual se definieron { } y se deben declarar antes
de utilizarlas:
Aquí ya no existe tmp2
Aquí existe tmp y tmp2
Aquí no existe ni tmp ni tmp2
Aquí existe tmp
16. Ambito de variables por bloques
Las variables (locales) sólo existen en el bloque
en el cual se definieron. Los bloques se definen
por { }
Si aquí se hace una referencia a b, aparecería un
error de compilación
17.
18. Variables auto
auto es una palabra reservada de C que se
supone que sirve para definir las variables
locales. Como este es el comportamiento
implícito de las variables en una función, dicha
palabra nunca se usa.
Dicha palabra es inútil y existe porque la heredó
el lenguaje C de su predecesor, el lenguaje B.
20. Cuidados con las variables globales
Póngale a las variables globales un nombre con
sentido:
int i; // mal nombre para una variable global
int NUM_MAX_ITERAC; // buen nombre para una variable global
Unicamente declare variables globales cuando
sea estrictamente necesario. Nunca las utilice si
una variable estática podría hacer el mismo
trabajo.
21. 21
Uso de la memoria RAM
● Código del programa, las constantes cadena y las
constantes #define se guardan en el segmento de código
(code segment)
● Variables globales, constantes globales creadas con const y
variables static se crean en el segmento de datos (data
segment); si no se han inicializado se guardan en un
subconjunto del segmento de datos llamado .bss. Cualquier
variable dentro del .bss se inicializa a cero.
● Variables locales (variables auto) (variables creadas en
bloques {}), constantes locales creadas con const y
llamados de funciones se crean en la pila de llamadas (call
stack). La pila tiene un tamaño limitado por el sistema
operativo. Modelo de memoria LIFO.
● Memoria dinámica (malloc) se toma del montón (heap) y se
accede usando punteros.
22. 22
La pila de llamadas (call stack)
http://en.wikipedia.org/wiki/Call_stack
La pila de llamadas o simplemente “la pila” es una estructura dinámica
de datos LIFO, que almacena la información sobre las subrutinas activas
(aquellas que se han llamado pero todavía no han completado su
ejecución) de un programa. La principal razón de su uso, es seguir el
curso del punto al cual cada subrutina activa debe retornar el control
cuando termine de ejecutar.
La pila de llamadas está compuesta por los llamados marcos de pila
(stack frames). Un marco de pila incluye la siguiente información:
● los argumentos (parámetros) pasados a la función;
● la dirección de memoria del código que se debe seguir ejecutándose
una vez se retorne de la función (dirección de memoria que está
dentro del segmento de código correspondiente a la función
llamante);
● espacio para las variables locales de la función.
23. 23
La pila de llamadas (call stack)
http://en.wikipedia.org/wiki/Call_stack
Aquí la DrawLine() está corriendo actualmente, y fue
llamada por DrawSquare()
25. 25
Paso de parámetros:
por valor o por referencia
Por valor: se hace una copia local de la
información dentro de la función y por lo tanto el
valor original no cambia.
Por referencia: se transfiere la dirección de
memoria de la variable con un puntero y por lo
tanto cualquier cambio a la variable hecha por la
función se observa en la función invocadora. Se
hace para cambiar el valor de la variable, o
cuando los datos a pasar son muy grandes y se
quiere acelerar los cálculos o conservar la
memoria.
26. 26
x se está pasando por valor
y se está pasando por referencia
z es la salida de la función
Declaración de la función
Definición de la función
Llamado de la función
30. 30
Como hacer una función que
devuelva más de dos variables?
2. Retornando una estructura que contiene los
valores deseados:
31. 31
Como hacer una función que
devuelva más de dos variables?
3. Utilizar un híbrido: pasar un puntero a una
estructura, que posteriormente es llenada:
32. 32
Punteros a variables estáticas
Como las variables estáticas se crean en el
segmento de datos, un puntero a una variable
estática siempre será válido incluso después de
haberse salido de la función.
HACER EJEMPLO
33. 33
Variables estáticas cuando se
tienen varios hilos (threads)
El C11 definión la palabra clave _Thread_local:
static _Thread_local int mivariable = 10;
Con esta palabra, cada hilo tendrá una variable
estática diferente.
34. 34
Funciones recursivas
http://en.wikipedia.org/wiki/Recursion_%28computer_science%29
Son funciones que se llaman a si mismas.
Se debe poner mucho cuidado al escribir una
función recursiva ya que esta no se debe llamar a
si misma indefinidamente; debe haber un punto
en el que la función en verdad retorne un valor.
De lo contrario la función agotará toda la memoria
de pila disponible en el computador y este
terminará.
36. 36
Se debe tener en cuenta que las funciones
recursivas pueden agotar la memoria de pila.
37. 37
Funciones inline
http://en.wikipedia.org/wiki/Inline_function
Con esta palabra, definida en C99, se solicita al
compilador (si es posible) que inserte el cuerpo completo
de la función en cada lugar donde se llama esta, en vez
de generar código que llame a la función. El compilador
no está obligado a cumplir esta instrucción. Esta
instrucción es útil para incrementar la velocidad del
código y se utiliza generalmente con funciones muy
pequeñas. Bjarne Stroustrup, el creador de C++, sugiere
que no se deben emplear macros (#define) para hacer
funciones pequeñas sino que se deben utilizar funciones
inline.
En el C99 el inline solo se puede colocar en el prototipo.
Si se pone en la definición de la función, habrá error de
compilación.
39. 39
Funciones anidadas
GNU C extension
Una función anidada (nested) es una
función encapsulada dentro de otra
función. Solo puede ser llamada por la
función que contenedora o por las
funciones anidadas en el mismo nivel.
Se utilizan para ocultar procedimientos
que sólo son útiles localmente. Se
deben definir junto con la declaración
de variables al principio de la función.
40. La función main()
Es obligatoria ya que es el punto de entrada al
programa.
El standard C permite los siguiente formas de
invocar a main():
No es necesario escribir una declaración para
main().
Debe retornar siempre un int
41. Valores que retorna main()
0 = EXIT_SUCCESS indica que el programa
terminó correctamente.
1 = EXIT_FAILURE indica que el programa
terminó con un error
Estas constantes están definidas en stdlib.h
42.
43.
44. main() con parámetros
Ver: http://www.gnu.org/software/libc/manual/html_node/Program-Arguments.html
argc (argument count) contiene el número de parámetros recibidos
por el programa (incluyendo el nombre del programa mismo).
argv (argument vector) es una matriz de punteros a cada uno de los
parámetros en el mismo orden en que fueron recibidos.
Es lo mismo que char **argv
El primer elemento del arreglo
argv[0] contiene el nombre del
programa (como se invocó). argv[1]
indica el primer parámetro pasado
al programa; argv[2] el segundo
parámetro, y así sucesivamente.
45. La función getopt()
● Está definida en unistd.h, se utiliza para
procesar opciones en línea de comandos, tal y
como es común en la aplicaciones de consola.
● Soporta opciones de
● un carácter: -a
● múltiples opciones especificadas al mismo tiempo:
-a -b y -c se especifican como -abc
● opciones con argumentos: -a arg, -i 3
● Ver:
http://en.wikipedia.org/wiki/Getopt
http://www.gnu.org/software/libc/manual/html_node/Getopt.html
$ man 3 getopt (en Linux y MacOS)
46. La función getopt_long()
● Está definida en getopt.h, es una versión
avanzada de getopt().
● Soporta opciones como:
● un carácter: -a o de un nombre --name
● múltiples opciones especificadas al mismo tiempo:
-a -b y -c se especifican como -abc
● opciones con argumentos -a arg, --name=arg, -i 3
Ver:
http://en.wikipedia.org/wiki/Getopt
http://www.gnu.org/software/libc/manual/html_node/Getopt.html
$ man 3 getopt (en Linux y MacOS)
47. 47
void exit (int exitcode);
Hace que el programa termine de forma natural.
Está definida en stdlib.h
exit(EXIT_SUCCESS); es equivalente a return 0;
exit(EXIT_FAILURE); es equivalente a return 1;
En Linux/BSD existe la librería sysexits.h la cual
contiene varios códigos de error.
48. 48
Funciones variádicas
http://en.wikipedia.org/wiki/Variadic_function
Son funciones que toman un número variable de
argumentos, que de algún modo se debe saber
con antelación.
Se necesita especificar al menos un parámetro de
un tipo de dato conocido. Los siguientes
parámetros son opcionales y pueden variar en
cantidad y en tipos de datos.
Se definen usando la librería stdarg.h.
Ver:
http://www.gnu.org/software/libc/manual/html_node/Argument-Macros.html#Argument-Macros
50. 50
Llamado de funciones a través de
punteros a funciones
http://en.wikipedia.org/wiki/Function_pointer
Un puntero a función es un tipo de puntero el cual en vez
de referirse a datos, se refiere a la dirección del código
ejecutable correspondiente a una función el cual se
encuentra dentro de la memoria. Al invocar la función a
la cual el puntero apunta, se ejecuta dicho código.
Aparentemente su uso es complicado, pero si se domina
su uso, pueden ser fuente de una programación
extremadamente eficiente y elegante.
Ver: http://www.newty.de/fpt/