FUNCIONES

En este bloque se tratarán problemas de programación que utilicen funciones, únicamente con tipos de datos simples y en la mayoría de los casos numéricos.



Ejemplo PERMUREP: Escribir un programa que calcule las permutaciones de N elementos donde hay M elementos iguales (y todos los demás diferentes), introduciendo N y M por teclado.
El resultado es el factorial del número de elementos totales dividido por el factorial de los elementos repetidos. Por tanto, ya que hay que calcular dos veces un factorial, lo escribiremos como una función factorial que será usada dos veces desde el programa principal.

/* PERMUREP */
#include <stdio.h>

int factorial(int num);

main()
{
  int n,m,perm;

  printf("Cual es el numero de elementos? ");
  scanf("%d",&n);  
  printf("De los %d elementos, cuantos hay repetidos? ", n);
  scanf("%d",&m);

  perm=factorial(n)/factorial(m);
  printf("Las permutaciones posibles de %d elementos habiendo %d repetidos son %d\n",n,m,perm);
}

int factorial(int num)
{
int i, result;

result=1;
for(i=2;i<=num;i++)
  result *= i;

return result;
}

Problema COMBINAF: Escribir un programa que utilice la función factorial para calcular el número combinatorio de N sobre M, ambos números naturales.
 
Orientación
Solución


Problema MCD3: Escribir una función que devuelva el máximo común divisor de dos números naturales (se puede obtener mediante el algoritmo de Euclides) y utilizarla en un programa que calcule y muestre el máximo común divisor de tres números naturales introducidos por teclado, aprovechando que la operación de calcular el M.C.D. es asociativa.
 
Orientación
Solución


Problema MCMSERIE: Escribir una función que devuelva el mínimo común múltiplo de una serie de números naturales introducidos por teclado, considerando que la serie se acaba cuando se introduce un cero o un número negativo (aprovéchese que la operación de calcular el m.c.m. es asociativa).
 
Orientación
Solución


Problema BINOMIO: Escribir un programa que calcule y muestre de mayor a menor grado los coeficientes del polinomio resultante de calcular (ax+b)n , dados a, b y n por teclado (para la solución de este problema recuérdese o consúltese el desarrollo del binomio de Newton).
 
Orientación
Solución


Ejemplo DOBLAR: En las funciones que hemos observado el valor de los argumentos en la llamada a la función se asignaba como valor a los argumentos que figuran en la función, en lo que se conoce como paso por valor, que no modifica en absoluto las variables de la función desde donde se llama (excepto aquella a la que se pueda asignar el resultado). Sin embargo hay ocasiones en que se desea que una función modifique el valor de alguna variable de la función que llama; entonces se precisa el paso por referencia, que en C se hará mediante punteros (que se trabajarán en profundidad más adelante).
Obsérvese la diferencia entre los dos programas siguientes:
 

#include <stdio.h>

int doble(int num)
{
num = num*2;
return(num);
}

main()
{
int a,b;

a=2;
b=doble(a);
printf("a=%d ; b=%d\n", a,b);
}

#include <stdio.h>

int doblar(int *num)
{
(*num) = (*num)*2;
return(*num);
}

main()
{
int a,b;

a=2;
b=doblar(&a);
printf("a=%d ; b=%d\n", a,b);
}

La función doble trata su argumento por valor, de modo que al llamar a la función, se le pasa el valor de a, que es 2, y ese valor se le asigna en la función al argumento que se llama num, y que se puede utilizar como cualquier otra variable local de la función. De hecho num pasa a valer 4, que es el valor que se devuelve y se asigna a la variable b, mientras que a no ha sido modificada. El programa escribe a=2 ; b=4 .
  Sin embargo en la función doblar se le pasa la referencia a la variable a (de hecho, en C &a es la dirección de la misma), que dentro de la función es referida como *num, con un valor inicial igual al que tuviera a, y todo lo que se haga con ella (doblarla) se está haciendo con la a. Así la función devuelve 4 que se le asigna a la b, pero además la a ha sido modificada y el programa escribe a=4 ; b=4 .



Ejemplo DIVENTERA: Escribir una función que devuelva el cociente y el resto de la división entera de dos números enteros que se le pasen como argumento, y un programa que muestre su utilización.
En este caso se pretende que una función devuelva dos valores, lo cual no es posible. Por ello se recurrirá al paso por referencia de la variable (o variables) a la cual queramos asignar resultado. De este modo el programa podría adoptar cualquiera de las dos siguientes formas, ambas con exactamente el mismo resultado.
 

#include <stdio.h>

int dv1(int dvo, int dvr, int *res)
{
*res = dvo % dvr;
return( dvo/dvr );
}

main()
{
int a,b,q,r;

a = 19;
b = 7;
q = dv1(a, b, &r);
printf("%d/%d = %d con resto %d\n", a,b,q,r);
}

#include <stdio.h>

void dv2(int dvo, int dvr, int *cc, int *res)
{
*res = dvo % dvr ;
*cc  = dvo / dvr ;
}

main()
{
int a,b,q,r;

a = 19;
b = 7;
dv2(a, b, &q, &r);
printf("%d/%d = %d con resto %d\n", a,b,q,r);
}



Problema INTERCAM: Escribir una función que intercambie el valor de dos variables que reciba como argumentos, y un programa que la utilice.
 
Orientación
Solución


Problema SUMFRACR: Escribir una función que, dados 4 números enteros, considerados como numerador y denominador de dos fracciones, devuelva el valor real de la suma de las fracciones, y un programa que la utilice.
 
Orientación
Solución


Problema SUMFRACF: Escribir una función que, dados 4 números enteros, considerados como numerador y denominador de dos fracciones, permita obtener el numerador y el denominador (ambos enteros) de la fracción simplificada resultante de la suma, y un programa que la utilice.
 
Orientación
Solución


Problema FIBONAC: Escribir una función que produzca el término i-ésimo de la serie de Fibonacci, que se define como a0=1, a1=1 y an=an-1+an-2  y un programa sencillo que la utilice.
 
Orientación
Solución


Problema PRIMO: Escribir una función que indique si un número es primo y emplearla en un programa para escribir todos los números primos menores que 100.
 
Orientación
Solución


Problema PERFECTO: Escribir un programa (con las funciones que se estime pertinentes) que escriba todos los números perfectos menores que 1000. Se dice que un número es perfecto cuando es igual a la suma de todos sus divisores (incluyendo el 1 y excluyendo el propio número).
 
Orientación
Solución


Problema CIFRAS: Escribir una función que escriba las cifras de un número entero positivo, una cifra por línea, y un programa que la utilice.
 
Orientación
Solución


RECURSIVIDAD

Ejemplo FACTOREC: Escribir una función que calcule el factorial de un número, teniendo en cuenta que 0!=1, que 1!=1 y que N! = N * (N-1)! , y un programa que la utilice.
En este caso, para el cálculo del resultado de la función utilizamos tanto dos casos directos (los factoriales de 0 y 1) y una definición que se utiliza a sí misma (para calcular un factorial utilizaremos el cálculo de otro). Esto es lo que se conoce como recursividad, que está permitida en C (aunque no está permitido en algunos lenguajes más limitados, como Fortran77). El programa que implementaría esta solución es el siguiente:

/* FACTOREC */
#include <stdio.h>

int factor(int num)
{
if(num<2)
  return 1;
else
  return num*factor(num-1);
}

main()
{
int n,fac;

printf("Introduce un numero:");
scanf("%d",&n);
fac=factor(n);
printf("El factorial de %d es %d\n", n, fac);
}



Problema POTEREC: Escribir una función recursiva para calcular la potencia de un número real elevado a un exponente entero, y un programa que la utilice.
 
Orientación
Solución


Problema FIBOREC: Escribir una función recursiva para calcular el término i-ésimo de la serie de Fibonacci, y un programa que la utilice.
 
Orientación
Solución


Problema COMBIREC: Escribir una función recursiva para calcular  el número combinatorio de N sobre M, y un programa que la utilice, sabiendo que combi(n,n)=1 ; que combi(n,0)=1 ; y que combi(n,m)=combi(n-1,m)+combi(n-1,m-1)
 
Orientación
Solución


Problema CIFRAREC: Escribir una función recursiva para escribir las cifras de un número entero positivo, una cifra por línea, y un programa que la utilice.
 
Orientación
Solución

FUNCIONES Y CONTROL DE ERRORES

Ejemplo COMBINA2: Escribir una función que calcule el número combinatorio de N sobre M, usando a su vez la función factorial, y un programa que la utilice.
Puede suceder que una función reciba valores inadecuados (en el caso de la función que calcule el combinatorio, que reciba valores negativos o que M sea mayor que N). Sin embargo la función no debe escribir ningún mensaje de error, ya que lo que se está esperando es que se devuelva un valor.
Por eso, si no se quiere controlar los valores antes de llamar a la función, se puede hacer que en caso de que los valores recibidos no sean adecuados la función devuelva un valor que en otro caso no podría dar (por ejemplo, y en este caso, -1) y que desde donde se llamó a la función se controle el valor devuelto.
En otros casos, donde la función puede producir correctamente cualquier valor, se hará que la función devuelva un código indicando la corrección o no de su ejecución, y los valores resultantes se proporcionen mediante paso por referencia (este sería el caso de la función scanf y otras muchas funciones de las librerías estandar).


/* COMBINA2 */
#include <stdio.h>

int combi(int arriba, int abajo);
int factorial(int num);

main()
{
  int n,m,comb;

  printf("Cual es el numero de elementos? ");
  scanf("%d",&n);
  printf("De los %d elementos, cuantos se cogen? ", n);
  scanf("%d",&m);

  comb=combi(n,m);
  if(comb<0)
    printf("Los datos son inconsistentes\n");
  else
    printf("Las combinaciones posibles de %d elementos tomando %d son %d\n",n,m,comb);
}

int combi(int arriba, int abajo)
{
if( (arriba<0) || (abajo<0) || (arriba<abajo) )
  return -1;
else
  return factorial(arriba)/(factorial(abajo)*factorial(arriba-abajo));
}

int factorial(int num)
{
int result;

result=1;
while(num>1)
  result *= num--;

return result;
}


EJERCICIOS ADICIONALES CON FUNCIONES

Problema MENU: Implementa una función que desarrolle un menú de propósito general y un programa que la utilice. A dicha función le pasaremos como argumento el número de opciones del menú y dicha función escribirá por pantalla los siguientes mensajes:

Elije entre las diferentes opciones:

-opción 1: pulsa el 1;
-opción 2: pulsa el 2;
...
-opción N: pulsa el N.
La función debe devolver la opción elegida.
Mejorar posteriormente la función para asegurar que el usuario acabe introduciendo una de las opciones expuestas.
 
Orientación
Solución


Problema COMPLEJO: Escribe una función que calcule y devuelva el producto de dos números complejos y un programa que la utilice. Estos números están definidos y se pasan como 4 variables reales, C1R y C1I para el primer número complejo (donde R e I hacen referencia a la parte real y a la imaginaria) y C2R y C2I para el otro número complejo.
 
Orientación
Solución


Problema RAIZNEWT: El método de Newton para hallar la raíz cuadrada de un número real positivo X tiene gran interés ya que utiliza sólo sumas multiplicaciones y divisiones (algunas de ellas divisiones por 2 que son inmediatas para la máquina). El método consiste en lo siguiente: para calcular la raíz cuadrada de un número X tal que el cuadrado de la solución difiera de X menos de un cierto error E, comenzamos con la aproximación a = X/2. Si |(a*a)–X|<E paramos los cálculos y el resultado es a. Si no, reemplazamos a con la siguiente aproximación definida por (a + X/a) / 2. Entonces comprobamos si esta aproximación es lo suficientemente buena de la misma manera que antes lo hicimos. Si lo es, el cálculo finaliza y si no prosigue iterativamente, estando garantizado que la aproximación converge.
Escribe una función que implemente este método dados X y el error E aceptable, y un programa que la utilice.
 
Orientación
Solución


Problema CLAVE: Un sistema de claves está construido de manera que se proporcionan un número de cuatro cifras N y una letra mayúscula. La clave es correcta si la operación (N modulo 25) +65 proporciona el código ASCII de la letra de la clave. Escribe una función que tomando como entrada un número y la letra determine si constituyen una combinación correcta o no, y un programa que la utilice
Ej  7639  B  es una clave incorrecta. La correcta sería 7639  O.
Modificar después la función para que el sistema de claves consiste ahora en considerar el número con sus cifras al revés. Es decir, si introduzco 3456 A se debe comprobar el (6543 mod 25) + 65.
 
 
Orientación
Solución


Problema ACKERMANN: Escribir una función para calcular el resultado de la función de Ackermann aplicada sobre dos números naturales y un programa que la utilice. La función de Ackermann se define por lo siguiente:
A(0,n) = n+1                 si n>=0
A(m,0) = A(m-1,1)        si m>0
A(m,n) = A(m-1,A(m,n-1)) si ambos m>0 y n>0
 
Orientación
Solución

Propuestas de ejercicios 


Problema RAIZNENT: Escribir una función que calcule la raíz cuadrada de un número entero redondeada al entero más próximo mediante el método de Newton, y un programa que la utilice.
Problema FERMAT: El Teorema de Fermat para los números primos dice lo siguiente: sea p un entero positivo y considera el conjunto Zp+={1, 2, …, p-1}. Si p es primo se cumple que (ap-1  modulo p) = 1 para cualquier a perteneciente Zp+. Realmente, a los números que pasan el test de Fermat se les llama pseudoprimos ya que hay algunos enteros, muy pocos, llamados Números de Carmichael que pasan este test y no lo son. Implementa una función (puedes usar diseño descendente y modularizar en varias funciones si lo crees conveniente) que realice el test de Fermat.
Problema BINARIO1: Escribir una función que dado un número entero positivo muestre por pantalla su representación en el sistema binario de numeración, y un programa que la utilice.
Problema BINARIO2: Escribir una función que dado un número entero positivo muestre por pantalla su representación en el sistema binario de numeración con un número determinado de bits (que se le pase a la función como segundo argumento), y un programa que la utilice.
Problema ESCALERA: Una escalera puede subirse superando en cada paso un escalón o bien superando dos.
Por ejemplo una escalera de 3 peldaños podría subirse de las siguientes maneras: 1-1-1 ; 1-2 ; 2-1
Implementa una función recursiva que imprima por pantalla todas las posibles maneras de subir una escalera de n escalones y un programa que la utilice donde se indique el número de escalones (que se le pasa a la función como argumento).
(Ayuda: utilícese una estrategia de divide y vencerás)

al índice
al siguiente bloque de problemas