Documente Academic
Documente Profesional
Documente Cultură
Funciones 5
05.01 Introducción
Inicialmente los lenguajes de programación permitían que la lógica de los programas salte libremente de una a otra parte, a tal punto que
se le llamó programación espagueti, esto complicaba la lógica. Para superar este problema se desarrolló la programación
estructurada, que solo tiene las 3 primitivas lógicas, que acabamos de aprender:
1) Programación secuencial,
2) Estructuras de decisión,
3) Estructuras de repetición.
Se demuestra que aplicando estas 3 primitivas de programación se puede escribir cualquier programa: GENIAL!!! esto simplifica mucho;
pero aún tenemos efectos colaterales para programar en modo profesional: los anidamientos múltiples complican la lógica; los bloques
de instrucciones no son re-utilizables en situaciones similares y hay que repetir el código, por lo que los programas se hacen extensos;
no se agrupa con precisión bloques de instrucciones que ejecutan una tarea específica. Para resolver estas dificultades se desarrollaron
las funciones, veamos una panorámica que nos ubica, utilicemos una función muy sencilla, suma():
Atento:
Un programa compila de inicio a fin, línea 01 a la 16, de izquierda a derecha: si se usa una variable o función no definida
previamente reporta error de compilación.
La ejecución de un programa sigue un orden distinto al de la compilación; inicia al comenzar la main() -línea 08- y termina al
finalizar la main() -línea 16; las otras líneas se ejecutan solo si son llamadas desde la main(), la función suma() -líneas 03 a la
06- se ejecuta 6 veces por que es llamada en las líneas 10, 11, 12, 13, 14 y 15.
01 #include<cstdio>
02 // Definición de la función suma()
03 int suma(int m, int n){ // recibe valores y los aloja en las variables int m y n y retorna un valor int.
04 printf("suma: %d + %d = %d\n", m, n, m+n);
05 return m+n; // retorna el valor int m+n
06 }
07 // Definición de la main():
08 main(){
09 int m=3, n=2, k;
10 k = suma(2, 1+4); // llama y envía los valores 2 y 5 y k recibe 7
11 suma(m, n); // llama y envía los valores 3 y 2 y no utiliza el valor de retorno
12 suma(m, n*2); // llama y envía los valores 3 y 4 y no utiliza el valor de retorno
13 suma(4, m+1); // llama y envía los valores 4 y 4
14 suma(k, 2*3); // llama y envía los valores 7 y 6
15 printf("Final : %d + %d = %d\n", 2,1, suma(2,1)); // suma(2,1) retorna int 3
16 }
La salida es:
suma: 2 + 5 = 7
suma: 3 + 2 = 5
suma: 3 + 4 = 7
suma: 4 + 4 = 8
suma: 7 + 6 = 13
suma: 2 + 1 = 3
Final : 2 + 1 = 3
Sintaxis:
tipoSalida miFun(tipo1 var1, tipo2 var2, …) { … }
PÁGINA: 1
Lenguaje C++
• Para tener más de un valor de salida, vea el capítulo de apuntadores.
Ejemplo:
float cenAFar(float cen) { // convierte grados Centigrados a Farenheith
return cen * 1.8 + 32; // retorna un valor de tipo float especificado al definir la función
}
Función : cenAFar, convierte grados Centigrados a Fahrenheit
Entrada : un valor de tipo flotante que es asignado a la variable cen.
Salida : retorna el valor de tipo flotante: cen * 1.8 + 32
Regla: El número, tipo y orden de los argumentos debe ser igual al número, tipo y orden de parámetros respectivamente:
Definición de la función Llamando a la función
Ejemplo:
float miFun(int n, float x, ...) {….} // n, x, … son los parámetros. La salida de tipo float
...
miFun(2, 4.3, ...); // los argumentos 2, 4.3 … de tipo int y float respectivamente son asignados a n y x
Tambien se puede llamar:
Y = miFun(2+1, 4.3*z, ...); // Y debe ser de tipo float
Tenga en cuenta que al llamar a una función:
en el paso de argumentos a parámetros y al retornar valor de una función llamada
se aplica casting automático de ser necesario, lo cual puede producir los errores lógicos descritos en el capítulo de Programación
Secuencial.
Ejemplo:
int n = 4;
float t = 20, x;
Definición de función Llamadas válidas Llamadas no válidas
float cenAFar(float cen){ x = cenAFar(t); x = cenAFar(); // falta argumento
return cen * 1.8 + 32; x = cenAFar(20); x = cenAFar(3, 4); // demasiados argumentos
} x = cenAFar(10+10); printf("%d\n", cenAFar(10));
cenAFar(10+10); // el formato es int y cenAFar retorna float
cenAFar(2*n);
printf("%.2f\n", cenAFar(10));
cenAFar(otraFun()); // otraFun()
retorna float
PÁGINA: 2
Lenguaje C++
A parte de la correspondencia de tipos en las entradas y la salida; una función es independiente (encapsulada) en su interior:
1) Desde cenAFar() no podemos acceder a la variable t en la main(), y viceversa, desde la main() no podemos acceder a la variable
cen de cenAfar().
2) Los nombres de las variables son independientes, por ejemplo, podemos programar:
float cenAFar(float t){ // la t de cenAFar( ) es independiente de la t de la main(), simplemente son tocayas.
return t * 1.8 + 32;
}
Muchas veces se usa el mismo nombre de variables en diferentes funciones para mantener la mnemonía, por ejemplo t representa
temperatura dentro de varias funciones, pero la t de una función no tiene ninguna relación con la t de las otras funciones.
3) Las variables globales son vistas desde todas las funciones.
Ejemplos de funciones:
Función que no hace nada:
void nada(void){ }
main(){
nada();
}
Ejemplo:
Sintaxis : int printf("format", exp1, exp2, …);
Descripción: 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 → n = 8.
printf("\nNúmero caracteres impresos = %d", n);
Salida:
var = 12
Número caracteres impresos = 8
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 rango de visibilidad de una variable o función inicia en el lugar de su definición y termina al final del bloque que la contiene.
PÁGINA: 4
Lenguaje C++
fun1, fun2, … se llaman entre sí, y suelen formar una red como:
El diagrama anterior facilita la compresión de la lógica a los desarrolladores; pero al momento de programar, las funciones se deben
definir de abajo para arriba, para que no hayan errores de compilación:
#include<cstdio>
int fun12(...){...}
float funAB(.. ){..... }
char fun21(.. ){...}
void fun1(.. ){...}
int fun2(.. ){...}
main(){
….
}
Esto dificulta la comprensión del programa; para facilitar se introduce el concepto de:
prototipo de función el cual indica los tipos de entrada y el tipo de salida de la función que se definirá más abajo. Se escribe al inicio:
#include<cstdio>
void fun1(int, float, ... ); // prototipo de fun1 : observe el final con ;
int fun2(... ); // prototipo de fun2 : observe el final con ;
int fun12(... ); // prototipo de fun12 : observe el final con ;
float funAB(.. ); // prototipo de funAB : observe el final con ;
char fun21(... ); // prototipo de fun21 : observe el final con ;
main(){
…
fun2(... ); // llamando a fun2()
…
}
void fun1(int n, float x, …) {…} // define a fun1()
int fun2(.. ){…} // define a fun2()
int fun12(.. ){…} // define a fun12()
float funAB(.. ){..... } // define a funAB()
char fun21(.. ){...} // define a fun21()
Los prototipos deben indicar los tipos de datos; opcionalmente, pueden indicar nombres de variables, solo como referencia:
Definición de función Prototipos válidos Prototipos no válidos
int miFun(float x, int m){…} int miFun(float x, int m); // el más usado float miFun(float y, int n);
int miFun(float m, int x); int miFun(int y, int n);
int miFun(float, int); int miFun(int, float);
Ejecución de un programa
• Un programa inicia su proceso en la main(), sin importar donde esté ubicada: al inicio, al final o al medio.
• El programa termina al finalizar el bloque de la main().
PÁGINA: 5
Lenguaje C++
• En tiempo de ejecución: las variables de la main() son alojadas en la Random Acces Memory (RAM: memoria de acceso aleatorio) y
se desalojan al terminar la ejecución; las variables de las otras funciones son alojadas cada vea que son llamadas y se desalojan
inmediatamente al terminar su ejecución, para ahorrar memoria. Por lo tanto la main() sa aloja una sola vez, las otras funciones se
pueden alojar y desalojar varias veces, son volátiles.
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, facilita el mantenimiento, parametrización (una función se
ejecuta para cualquier valor de los argumentos), y en muchos casos simplifica la lógica dentro de las funciones. De acá en adelante
usaremos funciones casi siempre.
// funciones
main(){
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 2: El programa para ejecutar las 4 operaciones aritméticas ya fue presentado, a diferentes niveles, en los tres capítulos
anteriores, ahora vamos a completarlo profesionalmente. Escriba un programa que lea dos enteros m > 0 y n > 0, y 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: _
Ejecute la opción seleccionada, repita el proceso y salga (termine) con la opción 5.
Requerimientos:
Valide que la opción esté entre 1 y 5 // Use do.
Repita la operación completa hasta que se elija 5. // Use do.
Use funciones // prototipo, definición y llamar
Para ejecutar la operación seleccionada, use switch.
leerEntero operaciones
Programa:
// 05_03.c : 4 operaciones
#include<cstdio>
// 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;
PÁGINA: 7
Lenguaje C++
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++
}
Salida:
3+2=5
3-2=1
3*2=6
3 / 2 = 1.500000
Se podría tener una red muy grande y compleja de funciones que formarían bucles (loops), lo cual sería muy complejo de resolver en
tiempo de ejecución, por lo que debe evitarse, en lo posible. También se puede tener funciones que que se llaman a sí mismas
(recursivas), por ejemplo fun21() es llamada por fun2() y también se auto-llama.
Notas
La recursividad es una forma particular de repetición, generalmente implanta una repetición o una inducción matemática al revés,
ejemplo: sumar los n primeros números enteros a partir de 1:
Foŕmula Repetición Inducción
Suma = [n*(n+1)]/2 Suma = 1 + 2 + … + n Suma = n + (n-1) + .. + 1
La función debe terminar en algún momento: No auto-llamarse más, e iniciar el proceso de cierre de auto-llamadas.
Muchas veces se resuelven fácilmente procesos de repetición complejos; pero no siempre es recomendable usarla porque cada
vez que se auto-llama, la función ocupa un espacio adicional en memoria y esto puede superar el espacio disponible.
// 05_05.c : Calcular la suma de los n primeros números enteros de tres formas distintas
#include<cstdio>
int sumar(int n){
if(n==1) return 1; // fin de función, no se auto-llama
return n + sumar(n-1);
}
main(){ main(){ main(){
int n = 5; int n = 5, i, suma; int n = 5;
suma = 0;
PÁGINA: 9
Lenguaje C++
suma = n*(n+1)/2; for(i=1; i<n; i++) suma = += i; suma = sumar(n);
printf("La suma de los %d primeros enteros es: %d\n", n, suma);
}
Salida:
La suma de los 5 primeros enteros es: 15
Observe que la estructura de las dos funciones es similar, ¿Por qué una función recursiva fac( ) tiene return y mcd( ) no?
Sugerencia:
1) Compare las definiciones de mcd y factorial.
2) Compare los ciclos recursivos:
m n r mcd(m, n) Cierre mcd() n fact(n) Cierre de Fact()
22 4 2 4 4 * fact(3) 4* 6= 24
4 2 0 3 3 * fact(2) 3 * 2 = 6
4 2 0 2 2 2 2 *fact(1) 2 * 1 = 2
1 1 1
PÁGINA: 10
Lenguaje C++
Confirma tu poder:
/* 05_07.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<cstdio>
int primo(int n){
int i=2;
while(i*i <= n) if(n%i++==0) return 0;
return 1;
}
main(){
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 el uso de las repeticiones:
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; pero se probó para los puntos críticos y eso es un buen indicador.
Las reglas aprendidas en este mundo virtual, también se aplican en el mundo real, por ejemplo, haga la sinonimia:
Mundo Virtual Mundo Real
Funciones Personas
Programas, sistemas Actividades, tareas
PÁGINA: 11
Lenguaje C++
Ya conoce con precisión el fundamento, para integrar en el mundo virtual; lo mismo funciona en el mundo real, además debe 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.
1) Ingresar un entero positivo, imprima todos los primos menores o iguales al mismo, utilice funciones.
4) Calcule el factorial de n fac(n) utilizando una función recursiva; pruebe con fac(4) y fac(40).
5) 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: 12
Lenguaje C++
PÁGINA: 13