Funciones
Introducción
Un programa se escribe en modo lineal de inicio a fin. Antes los lenguajes de programación permitían saltos de una a otra parte, lo cual
complicaba la lógica, a tal punto que se le llamó programación espagueti. Para superar este problema se desarrolló la programación
estructurada, que solo tiene 3 primitivas, que acabamos de aprender:
1) Programación secuencial,
2) Estructuras de decisión, y
3) Estructuras de repetición.
Se permitió la sentencia break; dentro de una repetición o switch para saltar al final de ella y facilitar la salida.
Se demuestra que aplicando estas 3 primitivas de programación se puede escribir cualquier programa. GENIAL!!! Esto simplifica mucho;
pero tenemos efectos colaterales para programar en modo profesional. Los programas son difíciles de entender, hay muchos
anidamientos de todo tipo; las instrucciones no son reutilizables en situaciones similares y hay que repetir el código, los programas son
largos, difíciles de documentar, etc. Para resolver estas dificultades se desarrollaron: Funciones que ejecutan tareas específicas en
modo independiente.
Ya tenemos la información suficiente para tener una visión panorámica de nuestros estudios:
Tipo de programación Clasificación Temas
Estructurada: se aplica para Teoría básica Programación secuencial
resolver problemas aislados. Estructuras de decisión
Estructuras de repetición
Funciones
Manejo de variables Arreglos
complejas Apuntadores
Cadena de caracteres
Estructuras
Adaptación al hardware Memoria dinámica
Manejo de archivos
Orientada a objeto: se aplica Teoría básica Programación Estructurada
para resolver problemas de Clases y objetos
gran intercomunicación
Aplicación Se definen clases específicas que representan a objetos que
contienen datos y saben hacer funciones, ejemplo, las clases:
Profesor:
Datos: código, nombre, especialidad, etc.
Funciones: enseñar, calificar, etc.
Estudiante:
Datos: código, nombre, especialidad, etc.
Funciones: estudiar, dar examen, etc.
Definición de función
Una función es un bloque de instrucciones que ejecuta una tarea, por ejemplo, la función main(), que hemos ejecutado hasta ahora:
void main(void){ // inicio de función main
….
} // fin de main().
Dentro de Main() hemos programado todas las tareas, lo cual la sobrecarga de tareas difíciles de coordinar; podemos organizar el
progrma para que la main() ejecute las tareas de control general y otras funciones ejecuten tareas específicas, ejemplo:
01 #include<stdio.h>
02 int mitad(int n){ // Define e inicia mitad(): entra un entero, no hay salida
03 return n/2;
04 } // fin de mitad()
05 void main(void){ // Define e inicia main
06 int n = 8;
07 printf("n/2 = %d\n", mitad(n)); // llama a mitad() e imprime
08 } // fin de main().
Salida: n/2 = 4
PÁGINA: 1
Lenguaje C
Sintaxis de una función: Describe qué hace la función; pero no cómo lo hace:
tipoSalida nombreFunción(tipo1 var1, tipo2 var2, …) { … }
Ejemplo:
int miFun(float var1) { …: return 4;}
nombreFunción: miFun
Entrada : valor de var1, que es de tipo flotante.
Salida : un dato de tipo entero = 4
Notas:
• Para indicar que no hay entradas o salida se usa void:
void miFun(void) { …}
• Para indicar que no hay salida, utilice void.
• Si se requiere un solo valor de salida,se escribe, por ejemplo:
int mitad(…) // la salida es de tipo int
Una función que llama a otra, no está obligada a usar el valor de salida, ejemplo:
n = mitad(8); // Usa el valor de salida
mitad(8); // No usa el valor de salida
• Para tener más de un valor de salida, vea el capítulo de apuntadores.
La programación estructurada básica tiene un efecto colateral: el código resultante suele entremezclar (anidar) diferentes algoritmos y
muchas veces es necesario escribir los mismos bloques de código en varias partes; para escribir un programa “funcional”: organizado y
sin duplicados, aplicamos una estrategia de dos pasos:
1) Dividir (físicamente) el programa en funciones (partes)
• Cada función ejecuta una tarea específica y es independiente de las otras (opera en modo caja negra: las variables de una
función no son vistas por las otras; si tuvieran el mismo nombre, simplemente son tocayas, e independientes).
• Una variable global es vista por todas las funciones; pero si dentro de una función se define una variable con el mismo nombre,
se invisibilisa la variable global y se ve la local. Se recomienda altamente reducir el uso de variables globales ya que se les
puede cambiar el valor en cualquier función y eso causa descontrol de su valor.
¡Admírate, alégrate… !!!! Estamos usando magistralmente principios fundamentales (dividir e integrar) de simplificación que lo usan
todas las ciencias, la gestión y el sentido común.
Ejemplo de función:
int leerNumero(void) {
int n;
printf("Ingrese un Número positivo: ");
scanf("%d", &n); // En este capítulo explicaremos el motivo por el que scanf() requiere &
return n; // retorna n
}
Sintaxis:
Componente Descripción
función Lee un entero > 0
Entradas ninguna
Salida Retorna un valor leído
Ejemplo de función:
float dividir(int m, int n){ // si m = 3 y n = 2
return m/(float)n; // se retorna 1.5 (tipo float)
}
Sintaxis
Componente Descripción
función Divide dos números
Entradas int m e int n
Salida m/n de tipo float
Ejemplo:
int printf("format", exp1, exp2, …);
Sintaxis: Imprime una lista de expresiones
Entradas: format: formato para escribir las expresiones
exp1, exp2, … : lista de expresiones a imprimir
Salida: Imprime en el monitor y retorna el número de caracteres escritos.
Ejemplo:
int n, var = 12;
n = printf("\nvar = %d", var); // imprime: var = 12; se imprimen 8 caracteres.
printf("\nNúmero caracteres impresos = %d", n); // imprime: Número caracteres impresos = 8
Salida:
var = 12
Número caracteres impresos = 8
Ejemplo:
int a;
float b;
scanf("%d %f", &a, &b); // tipee: 12 5.621<enter> La separación entre formatos debe ser 1 espacio.
printf("a = %d, b = %.2f\n", a, b); // el formato %.2f indica que solo se impriman 2 decimales
Salida:
a = 12, b = 5.62
Estructura de un programa
Imagine un departamento de trabajo en la vida real con un jefe y varios subordinados, un programa funciona de modo similar,
reemplazando personas por funciones.
PÁGINA: 3
Lenguaje C
Escritura y compilación:
1) Se lee y compila de arriba hacia abajo y de izquierda a derecha
2) Primero se define una variable o función y luego se utiliza en cualquier parte.
3) El alcance de uso de una variable o función inicia en el punto donde se define y termina al final del bloque (o programa) que la
contiene.
Ejemplo de programa que contiene todas las componentes:
#include<miLibrería> // incluye el archivo miLibrería que contiene funciones a ser usadas
...
#define PI 3.1416 // Define constantes de dos modos
const float E = 2.7172;
...
int miGlobal = 4; // define variables globales
...
tipo miFun1(….) { … } // define funciones
….
// mas componentes de cualquier tipo.
Esto funciona muy bien para programas muy sencillos; para complejos se divide en funciones:
Diagrama:
Este diagrama, en dos dimensiones, facilita la compresión de la lógica de un programa en particular, pero al momento de escribirlo en
una dimensión y cumplir lar reglas de estructuración, se debe escribir de abajo para arriba:
01 #include<stdio.h>
02 .. fun12(...){...}
03 .. funAB(.. ){..... }
04 .. fun21(.. ){...}
05 .. fun1(.. ){...}
06 .. fun2(.. ){...}
07 void main(void){
08 ….
09 }
Si la red de funciones es pequeña, no es problema escribirla patas arriba; pero si es mediana o grande, será difícil entenderla. El
lenguaje C utiliza prototipos de funciones. Un prototipo es una declaración de una función. Ejemplo, para el programa anterior:
Primero escriba los prototipos en cualquier orden.
A continuación las funciones en cualquier orden.
• Los prototipos se definen al inicio del programa, esto permite definir las funciones en cualquier parte. Si se escribe una función antes
de ser llamada no es necesario su prototipo; si se escribe después, sí es necesario.
• Las funciones pueden llamarse entre ellas muchas veces, inclusive pueden autollamarse (recursividad); el programador es
responsable de que no se formen círculos viciosos.
• Se coordina el número, orden y tipo de datos que se usan: deben ser iguales en los 4 lugares de uso; supongamos la función:
float dividir(int m, int n) por ejemplo:
Ejemplo:
...
float dividir(int m, int n); // 4) prototipo
…
void main(void){
int m=10, n=1; float p; // 1) definición de variables
...
printf("m = %d, n = %d, m/n = %.2f\n", m, n, dividir(m, n+1)); // 2) llamada: 1
...
p = dividir(4, 3); // 2) llamada: 2
...
}
...
float dividir(int m, int n){ // 3) definición
// recibe valores que se almacenan en m y n: la primera vez recibe: 10 y 2; la segunda: 4 y 3
return (float)m/n;
}
se debe coordinar en el orden operativo siguiente:
1) En la función que llama, al definir variables : int m, n; float p; // m, n son de tipo int; p es float
2) En la función que llama, al llamar : dividir(m, n); p = miFun(9, 2); // 2 argumentos de tipo int, y el retorno es float
3) Al definir la función : float dividir(int m, int n){ … } // 2 parámetros de tipo int, y el retorno es float
4) Al definir el prototipo : float dividir(int m, int n); // 2 parámetros de tipo int, y el retorno es float
ATENCION, ATENCION, Gran cambio de mentalidad: Hasta este momento, el uso de funciones puede parecer artificioso, trabajoso y
confuso; sin embargo nos da orden, independencia, división del trabajo, mantenibilidad, y en muchos casos simplifica la lógica. De acá
en adelante usaremos funciones siempre que sea “recomendable”
PÁGINA: 5
Lenguaje C
Ejemplo:
// 04_01.c : Leer dos números m. n > 0 y divídir m/n
#include<stdio.h>
// prototipos
int leerNumero(void); // 4) prototipo
float dividir(int m, int n); // 4) prototipo
// funciones
void main(void){
int m, n; // 1) Definir variables
m = leerNumero(); // 2) llama a leerNumero: no envía valor, recibe valor int
n = leerNumero(); // 2) llama a leerNumero
printf("m = %d, n = %d, m/n = %.2f\n",m, n, dividir(m, n)); //
}
int leerNumero(void){ // 3) Definir función: Entrada: no hay; salida: valor int
int n=0;
do {
printf("Ingrese un entero positivo: ");
scanf("%d", &n);
} while(n<=0);
return n;
}
float dividir(int m, int n){ // 3) Definir función: Entrada, salida
return m/(float)n;
}
Salida:
Ingrese un número positivo: 3
Ingrese un número positivo: 2
m = 3; n = 2; m/n = 1.50
Ejemplo 1: Vamos a programar el mismo algoritmo de números primos en 3 contextos. Observe cuidadosamente los pequeños cambios
en:
• Los nombres de las variables
• Las condiciones de inicio y fin de los bucles
• Los cambios de código en el cuerpo de los bucles
// 04_04.c : Determinar si un número es primo
Ingrese un número n > 1 y determine Ingrese un número m > 1 y liste todos los primos <= m
si es o no primo
Utilizando anidamientos Utilizando funciones
PÁGINA: 6
Lenguaje C
#include<stdio.h>
int primo(int n);
void main(void){
int n, primo=1, i=2; int m, n, primo, i; int m, n;
printf("Ingrese un entero > 1: "); printf("Ingrese un número > 1: "); printf("Ingrese un número > 1: ");
scanf("%d", &n); scanf("%d", &m); scanf("%d", &m);
for(n = 1; n<= m; n++){ for(n = 2; n<= m; n++)
primo = 1;
i = 2;
if(n==1) primo = 0; // algoritmo primo
else while(i*i <= n && primo) if(n%i++==0) primo=0;
if(primo) printf("%d es primo\n", n); if(primo(n)) printf("%d es primo\n", n);
else printf("%d no es primo\n", n); else printf("%d no es primo\n", n);
}
} int primo(int n){ // algoritmo primo
if(n==1) return 0;
int i=2;
while(i*i <= n) if(n%i++==0) return 0;
return 1;
}
}
Ejemplo 2: El algoritmo de las 4 operaciones ya fue presentado en los dos capítulos anteriores, ahora lo vamos a completar. Escriba un
programa que lea dos enteros m > 0 y n > 0, luego presente el menú:
Operación que requiere:
1) Sumar: m + n
2) Restar: m – n
3) Multiplicar: m * n
4) Dividir: m/n
5) Salir
Elija su opción: _
Indicaciones:
Valide que la opción esté entre 1 y 5 // Use do.
Ejecute la operación seleccionada. // Use switch.
Repita la operación completa hasta que se elija 5. // Use do.
Utilice funciones // de esta manera el main() ejecuta solo funciones de control
// 04_05.c : 4 operaciones
#include<stdio.h>
// prototipos
int leerEntero(void);
void operaciones(int m, int n);
int menu(void);
void suma(int m, int n);
void resta(int m, int n);
void multiplicacion(int m, int n);
void division(int m, int n);
int leerEntero(void){
int m;
printf("Ingrese un entero > 0: ");
scanf("%d",&m);
return m;
}
void operaciones(int m, int n){
int op; // op = opción
do { // Repetición de operación completa hasta que se elija 5.
op = menu();
switch(op){ // Ejecute de operación seleccionada.
case 1: suma(m,n); break;
case 2: resta(m,n); break;
case 3: multiplicacion(m,n); break;
case 4: division(m,n); break;
default: printf("Gracias por su visita\n");
}
} while(op!=5);
}
int menu(void){
int op;
printf("\nOperación que requiere:\n");
printf("1) Sumar: m + n\n");
printf("2) Restar: m – n\n");
printf("3) Multiplicar: m * n\n");
printf("4) Dividir: m/n\n");
printf("5) Salir:\n");
do { // Valida la opción entre 1 y 5
printf("Elija su opción: "); scanf("%d",&op);
} while (op<1 || op > 5);
return op;
}
void suma(int m, int n) {printf("suma = %d\n", m+n);}
void resta(int m, int n) {printf("resta = %d\n", m-n);}
void multiplicacion(int m, int n) {printf("multiplicación = %d\n", m*n);}
void division(int m, int n) {
if(n==0) printf("No se puede dividir, divisor = 0");
else printf("división = %.2f\n", (float)m/n);
}
PÁGINA: 8
Lenguaje C
void por (int m, int n){printf("%d * %d = %d\n", m, n, m*n);}
void div (int m, int n){
if(n==0) printf("No se puede dividir entre 0\n");
else if(m%n==0) printf("%d / %d = %d\n", m, n, m/n);
else printf("%d / %d = %f\n", m, n, (float)m/n);
}
Salida:
3+2=5
3-2=1
3*2=6
3 / 2 = 1.500000
Hemos dicho que se pasa como argumentos y recibe como parámetro: valores; pero una función es un código y
no tiene un valor; mmm si tiene un valor, ¿Cuál?
Función recursiva
Un programa puede contener varias funciones, las cuales suelen tener una estructura casi jerárquica:
Notas
Estas funciones son útiles para resolver problemas de recursividad; aunque también se suelen usar como alternativa a los
procesos iterativos (do, while, for), lo cual no es recomendable porque cada vez que se autollama ocupa un espacio adicional en
memoria y esto puede superar el espacio disponible.
La función debe terminar en algún momento: No autollamarse más e iniciar el proceso de cierre de autollamadas.
// 04_07.c : Calcular la suma de los n primeros números enteros de tres formas distintas
#include<stdio.h>
int suma(int n);
main(void){
int n = 5, i, sum = 0;
// Iterando
for(i=1; i <= n; i++) sum += i;
printf("La suma de los %d primeros enteros es: %d\n", n, sum);
Confirma tu poder:
/* 04_09.c : Verificar si un número n es primo o perfecto (n es perfecto,
si n = suma de sus divisores, ejemplo: 6 = 1 + 2 + 3; 28 también lo es)
*/
#include<stdio.h>
int primo(int n){
PÁGINA: 10
Lenguaje C
int i=2;
while(i<n && i*i <= n) if(n%i++==0) return 0;
return 1;
}
void main(void){
int n, i=2;
printf("Ingrese un entero > 0: ");
scanf("%d", &n);
Matriz de Pruebas
Descripción Entrada Salida Chequeo
1 Valor inicial 1 1 es primo 1 es perfecto √
2 Valor inicial 2 2 es primo 2 no es perfecto √
3 Valor medio 3 3 es primo 3 no es perfecto √
4 Valor medio 5 5 es primo 5 no es perfecto √
5 Valor significativo 6 6 no es primo 6 es perfecto √
6 Valor significativo 28 28 no es primo 28 es perfecto √
7 Valor mayor 29 29 es primo 29 no es perfecto √
8 Valor mayor 30 30 no es primo 30 no es perfecto √
¡Perfecto, Admírate!:
¡Qué fácil! : Fíjate en los return de las funciones;
¡Qué óptimo!: Fíjate:
Para primo : while(i<n && i*i <= n) if(n%i++==0) return 0;
Para perfecto: for (i=2;i<=n/2; i++) if(n%i==0) suma += i;
Aunque la máquina es rapídisima y no protesta; en ambos casos, no hicimos ni un cálculo demás.
¡Qué claro! : Fíjate en la main(), solo ordena; y las funciones solo ejecutan, y no hay chismes (corrupción de información): Lo que
está en la main(), se queda en la main; lo que está en una función se queda en la función; solo se comunica lo indispensable.
¡Qué ingenioso!: Fíjate como se manejaron las estructuras repetitivas. Pronto serás diestro en eso.
¡Qué bien probado!: mmm; eso no es verdad; está comprobado para 8 valores; pero eso no significa que esté probado para todos
los valores; sin embargo es un buen indicador: el algoritmo, el programa y los casos de prueba críticos has sido cubiertos.
Resumen de funciones
1) Se divide el programa (divide y vencerás) en funciones: bloques lógicos que actúan como caja negra.
2) Se integran las funciones, cada función hace su tarea (función), por ejemplo, la main() -principal- va a ser principal de verdad y
no una función "todera"; la main() debe contener solamente las variables principales del programa y delegar las tareas a sus
funciones asistentes.
Es más fácil controlar funciones aisladas, con sus propias variables y algoritmos; pero hay que ser preciso en la comunicación
entre ellas. Cuando la main() ejecuta varias tareas, las variables y algoritmos están juntos y revueltos, esto es muy frecuente en
los anidamientos de procesos repetitivos.
3) Las funciones se comunican del modo más "funcional", privado y seguro posible:
• La función no revela cómo hace su tarea, actúa como caja negra.
• Se trata de que los valores de entradas y salida sean lo más generales posible, a esto se le llama paramétrización; para ello
PÁGINA: 11
Lenguaje C
es determinante establecer con precisión:
Los tipos de datos
Las cantidad de datos
de las entradas y de la salida.
• La función recibe copia de los datos de entrada, puede cambiarlos, eso no afecta a la variable en la función que llama.
• Una función retorna un solo valor, o nada.
• Las variables definidas dentro de la función no son visibles fuera de ella, se crean en la RAM cada vez que se llama a la
función y se eliminan al terminar la misma.
• Las variables definidas en otras funciones no son visibles; por lo tanto pueden tener los mismos nombres. Las variables
globales sí son visibles en todas las funciones; si define una variable con el mismo nombre dentro de una función, se
superpone sobre la global y la invisibiliza. Reduzca al mínimo indispensable las variables globales ya que su valor puede ser
cambiado inadvertidamente en cualquier parte; para evidenciar que una variable es global, se suele escribir su nombre en
mayúsculas.
4) Si un proceso se repite más de una vez, escriba una función y llámela desde varios sitios.
5) El uso de funciones es un tanto engorroso para programas sencillos.
6) Si usa funciones, su programa será mucho más fácil de entender y mantener.
Ya entendiste las funciones, pronto aprenderás y ganarás maestría.
Las reglas aprendidas en este mundo virtual, también se aplican en el mundo real, haga la sinonimia:
Mundo Virtual Mundo Real
Funciones Personas
Programas, sistemas Grupos de personas, organizaciones
Ya conoces con precisión el fundamento, para integrar en el mundo virtual, el mismo funciona en el mundo real; pero debes añadir el
sentimiento y la acción de las personas.
Fuente: https://www.google.com.pe/url
Atent@: Tu mamá le contará a todo el mundo: ¡Mi niñ@ es tod@ un@ profesional de la computación!
Espero que tengas a la mamá; ella tiene algo de razón. Hemos avanzado bastante en la teoría, luego manejaremos tipos de datos más
complejos y útiles.
5) Calcule el factorial de n fac(n) utilizando una función recursiva; pruebe con fac(4) y fac(40).
6) Utilice una función recursiva para calcular la función de Ackermann A(m,n), donde m >=0, n>=0 y:
n +1, Si m = 0;
A(m, n) = A(m-1,1), Si m > 0 y n = 0;
A(m-1, A(m, n-1)), Si m > 0 y n > 0
PÁGINA: 13