Anda di halaman 1dari 13

Lenguaje C

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, …) { … }

Salida Nombre Entradas Tarea


nombreFunción cumple las mismas reglas que el nombre de una variable.
Entrada: pueden haber 0 ó más con tipo1, tipo2, ...
Salida : Solo puede salir 0 ó 1 valor con tipoSalida
Ver capítulo apuntadores para más de 1 valor de salida

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.

• En el capítulo de Cadena de caracteres aprenderemos a utilizar main() con varias entradas

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.

2) Integrar (lógicamente) las funciones:


• Las funciones pueden formar una red, se recomienda que sea casi jerárquica con un jefe principal: la main(); el programador
es responsable de que el flujo entre las funciones no forme un círculo sin salida.
• Las funciones se escriben solo una vez y son llamadas de diferentes partes.
• Al llamar a una función se le pasa 0 ó más valores llamados argumentos, ejemplo, si n vale 8:
mitad(n);
no pasa la variable n, sino el argumento = 8.
Como argumento (valor) se pasa cualquier expresión, ejemplo:
mitad(4*2);
mitad(mitad(16)+2*otraFun(3));
miFun(n, 8.2); // los argumentos se separan con comas.
Los argumentos se reciben en la función llamada, en parámetros (variables), ejemplo:
int mitad(int n){ ... } // el parámetro (variable) n recibe el valor 8.
float miFun(int n, float x); // los parámetros se separan con comas.
Los tipos de datos del argumento deben ser iguales al de los parámetros CORRESPONDIENTES, ejemplo:
mitad(n); // argumento: valor de n = 8 es entero

int mitad(int n){ ... } // parámetro: variable n recibe un valor de tipo entero
Si no se envían argumentos a la función se escribe void como parámetro:
n = mifun(); // llama a miFun()
...
int mifun(void){….} // miFun() no recibe argumentos
• Al terminar una función puede o no retornar un valor, lo cual se debe especificar al inicio de la definición de la misma:
int miFun(int n) {…; return 4;} // el valor retornado debe ser del tipo especificado (int, en este caso)
La función que llama, puede o no utilizar el valor:
m = miFun(4); // utiliza el valor
PÁGINA: 2
Lenguaje C
miFun(4) // no utiliza el valor
Si no se retorma valor, se especifica void en la definición:
void mifun(int n) {…; } // no se escribe return
La función que llama no puede utilizar valor de retorno, puesto que no existe:
miFun(4); // correcto
m = miFun(4); // error de compilación

¡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.

Para ser ordenados, sigamos el diagrama lógico para prototipos y funciones:


01 #include<stdio.h>
02 .. fun1(... ); // prototipo de fun1 : observe el final con ;
03 .. fun2(... ); // prototipo de fun2 : observe el final con ;
04 .. fun12(... ); // prototipo de fun12 : observe el final con ;
05 .. funAB(.. ); // prototipo de funAB : observe el final con ;
06 .. fun21(... ); // prototipo de fun21 : observe el final con ;
07 void main(void){
08 ….
09 }
10 .. fun1(...){...} // define a fun1()
11 .. fun2(.. ){...} // define a fun2()
12 .. fun12(.. ){...} // define a fun12()
05 .. funAB(.. ){..... } // define a funAB()
13 .. fun21(.. ){...} // define a fun21()

Ejecución de un programa: ¡Sorpresa!: no se ejecuta en el mismo orden en que se escribe y compila.


• Un programa inicia su proceso en la main(), sin importar donde esté ubicada: al inicio, al final o al medio.
PÁGINA: 4
Lenguaje C
• El programa termina al finalizar el bloque de la main()

Protocolo de comunicación entre función que llama y función llamada


El objetivo es integrar de tal modo que haya:
Dependencia en la entrada/salida de datos: El orden, número y tipo de datos de entrada/salida debe ser el mismo
Independencia operativa: los nombres de las variables y la lógica interna son absolutamente privados

• 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

• NO se coordinan los nombres de las variables, y puede suceder:


• Omitir los nombres de las variables si no son necesarios, como es el caso en los prototipos
• Los nombres de las variables pueden ser distintos en distintos funciones, ejemplo:
int miFun(int m); // prototipo; Es correcto definir: int miFun(int);
void main(void){
int n = 4, z; // define la variable dentro de la main()
...
z = mifun(n+3) + miFun(2); // llama a la función, transfiere valores, no variables
...
}
int miFun(int k){ // define la función y los nombres de variables dentro de la función, los cuales pueden
// ser iguales o diferentes a los nombres correspondientes en la función.
} // Recibe valores, no variables
El nombre de una variable en una función se selecciona en base a la mnemonía adecuada dentro de ella; pero es recomendable
que la mnemonía sea a nivel de programa, para disminuir confusiones; ejemplo; si podemos usar en todos partes miFun( m), es
más adecuado para todo el programa. Evitar confusiones, por ejemplo si tiene miFun(int m, int n); evite llamarla con miFun(n,
m).
• Una función no ve las variables de otras funciones; si las variables tuvieran el mismo nombre, se trata de dos variables
independientes, en distinto ámbito.
• Una función ve a las variables globales, y les puede cambiar de valor; pero si define una variable con el mismo nombre, ya no ve
a la global.

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

Paso de argumentos a parámetos:


Cuando una función fun() llama a otraFun() le pasa argumentos a parámetros por valor. Sucede la secuencia de ejecución:
int otraFun(int m);
void fun() {
int m = 4, n; // (1) define m y n
n = otraFun(m); // (2) envía el valor el valor 4 (argumento) y espera un valor para n
// (5) n recibe el valor 6
printf("%d\n,", n);
}
int otraFun(int m) { // (3) recibe el valor 4 y lo asigna a la variable m (parámetro de otraFun())
return(m+2); // (4) salida del valor 6 que va para miFun
}
Salida: 6
En tiempo de ejecución, las variables de una función son alojadas en la Random Acces Memory (RAM: memoria de acceso aleatorio) al
momento de ser llamada; al terminar la misma, son desalojados inmediatamente para ahorrar memoria, de este modo, los espacios
alojados son volátiles.

Alcance de variables y funciones ver capítulo: Programación Estructurada


Las variables y funciones siguen las mismas reglas de alcance.
Una función es un bloque, por lo tanto, dentro de ella se puede ver y cambiar valores de las variables globales.

2 Ejemplos del cambio de paradigma de programación a funciones

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;
}
}

Aprecie las diferencias:


Aspecto Sin funciones Con funciones
Programa general Más complejo: Contiene la lógica general y los Más simple: Contiene la lógica general y llama a los algoritmos
algoritmos (funciones)
Algoritmo Ménos flexible: Definido dentro del programa Más fléxible: Definido en funciones independientes y puede ser
general, no puede ser llamado de otras partes. llamado de diferentes partes.
Comunicación Más simple Más compleja

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);

void main(void){ // main() solo ejecuta funciones de control


int m, n;
m = leerEntero();
PÁGINA: 7
Lenguaje C
n = leerEntero();
operaciones(m, 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);
}

Paso de argumentos de tipo función


Esta capacidad da mayor flexibilidad a la parametrización, ejemplo:
// 04_06.c : Paso de argumento de tipo función
#include<stdio.h>
void suma (int m, int n);
void resta(int m, int n);
void por (int m, int n);
void div (int m, int n);
void operaciones(int m, int n, void f(int m, int n));
void main(void){
int m= 3, n =2;
operaciones(m, n, suma); // Se pasa una función como argumento
operaciones(m, n, resta);
operaciones(m, n, por);
operaciones(m, n, div);
}
void operaciones(int m, int n, void f(int m, int n)){f(m, n);} // en general: {….; f(m, n); …..;}
void suma (int m, int n){printf("%d + %d = %d\n", m, n, m+n);}
void resta (int m, int n){printf("%d - %d = %d\n", m, n, 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:

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. Sin embargo, si puede ser útil tener funciones que que se llaman así mismas (recursivas), por ejemplo fun21() es llamada por
fun2() y se autollama; el autollamado debe detenerse en algún momento, porque si no, entramos en loop.

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;

// utilizando una fórmula


printf("La suma de los %d primeros enteros es: %d\n", n, n*(n+1)/2);

// Iterando
for(i=1; i <= n; i++) sum += i;
printf("La suma de los %d primeros enteros es: %d\n", n, sum);

// Utilizando una función recursiva:


printf("La suma de los %d primeros enteros es: %d\n", n, suma(n));
}

int suma(int n){


if(n == 1) return 1; // sale de la función como un break
return n + suma(n-1);
}
Salida:
La suma de los 5 primeros enteros es: 15
La suma de los 5 primeros enteros es: 15
La suma de los 5 primeros enteros es: 15

La función suma() se ejecuta en dos tiempos:


PÁGINA: 9
Lenguaje C
1 2
n suma(n) Cierre de suma()
5 5 + suma(4) 5 + 10 = 15
4 4 + suma(3) 4 + 6 = 10
3 3 + suma(2) 3+3=6
2 2 + suma(1) 2+1=3
1 1

Estrategia para programar funciones recursivas


Observe la función recursiva suma() anterior:
int suma(int n){
if(n == 1) return 1; // Poner la condiciones de fin de recursividad al inicio
return n + suma(n-1); // Poner las autollamadas al final
}
/* 04_08.c : Programar dos funciones recursivas con estructuras similares:
1) Hallar el máximo común divisor de dos enteros positivos m y n utilizando el método de Euclides.
2) Hallar el factorial de m.
*/
#include<stdio.h>
int mcd(int m, int n);
void main(void){
int m, n, temp;
printf("Ingrese dos números enteros mayores que cero: "); scanf("%d %d", &m, &n);
printf("El factorial de %d es: %d\n", m, fac(m)); // atento si m es grande se produce un overflow de fac()
if(m<n){ // primer número >= segundo número
temp = m;
m = n;
n = temp;
}
printf("El mcd de %d y %d es: %d\n", m, n, mcd(m,n));
}
int mcd(int m, int n){
if(m%n==0) return n; // sale de la función como un break
mcd(n,m%n);
}
int fac(int m){
if(m==1) return 1;
return m*fac(m-1); // sale de la función como un break
}

¿Por qué una función recursiva tiene return y la otra 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()


28 6 4 5 5 * fact(4)
6 4 2 4 4 * fact(3)
4 2 0 2 ...

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;
}

int perfecto(int n){


int i, suma = 1;
for (i=2;i<=n/2; i++) if(n%i==0) suma += i;
if(suma==n) return 1;
return 0;
}

void main(void){
int n, i=2;
printf("Ingrese un entero > 0: ");
scanf("%d", &n);

if(primo(n)) printf("%d es primo\n", n);


else printf("%d no es primo\n", n);
if(perfecto(n)) printf("%d es perfecto\n", n);
else printf("%d no es perfecto\n", 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.

Ubícate: Ya no eres un minino en computación:

Fuente: https://www.google.com.pe/url

¡Felicitaciones! Ya no dices miau y se te ve muy bien.


A la pinta se le suele dar más valor del que debiera y lo sabes bien; por eso no se te suben los humos, ni aunque en el espejo
apareciera Einstein: Tú eres tú.

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.

Ejercicios: Escriba, compile y ejecute los programas:


1) Ingresar un entero positivo, imprima todos los primos menores o iguales al mismo, utilice funciones.

2) Escriba 4 funciones, cuyos prototipos son:


int suma(int n, int m); // retorna n + m
int resta(int n, int m), // retorna n - m
int multiplica(int n, int m), // retorna n * m
float divide(int n, int m), // retorna n / m si m no es cero
Desde main(), llámelas e imprima los resultados.

3) ¿Cuáles son los valores de las variables en los comentarios: //?


//T04_03.c
#include<stdio.h>
#define PI 3.1416
int m = 1;
float k = 3;
int miFun(int n, int *m);
void main(void){
PÁGINA: 12
Lenguaje C
int j, m = 2;
j = miFun(4, &m); // m=2, k=4.0
...
}
int miFun(int n, int *m){
*m++;
k++;
printf("%d %d %f\n", n, *m, k);
return (2*k + *m + n); // n = 4, m = valor ilógico, j = no declarada, k = 4.0
}

4) Responda a las preguntas y argumente su respuesta:


a. ¿Puede una función llamar a main()? // Sí
b. ¿Es posible que una función a() llame a una función b(), esta a una función c(); y esta llame nuevamente a a()? // Sí
c. ¿Es posible que una función se llame a si misma? // Sí

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

Anda mungkin juga menyukai