7. Introducción a las funciones
7.1. Diseño modular de programas: Descomposición modular
Hasta ahora hemos estado pensando los pasos que deberíamos dar para resolver un cierto problema, y hemos creado programas a partir de cada uno de esos pasos. Esto es razonable cuando los problemas son sencillos, pero puede no ser la mejor forma de actuar cuando se trata de algo más complicado.
A partir de ahora vamos a empezar a intentar descomponer los problemas en trozos más pequeños, que sean más fáciles de resolver. Esto nos puede suponer varias ventajas:
- Cada “trozo de programa” independiente será más fácil de programar, al realizar una función breve y concreta.
- El “programa principal” será más fácil de leer, porque no necesitará contener todos los detalles de cómo se hace cada cosa.
- Podremos repartir el trabajo, para que cada persona se encargue de realizar un “trozo de programa”, y finalmente se integrará el trabajo individual de cada persona.
Esos “trozos” de programa son lo que suele llamar “subrutinas”, “procedimientos” o “funciones”. En el lenguaje C, el nombre que más se usa es el de funciones.
7.2. Conceptos básicos sobre funciones
En C, todos los “trozos de programa” son funciones, incluyendo el propio cuerpo de programa, main. De hecho, la forma básica de definir una función será indicando su nombre seguido de unos paréntesis vacíos, como hacíamos con “main”. Después, entre llaves indicaremos todos los pasos que queremos que dé ese “trozo de programa”.
Por ejemplo, podríamos crear una función llamada “saludar”, que escribiera varios mensajes en la pantalla:
saludar() {
printf("Bienvenido al programa\n");
printf(" de ejemplo\n");
printf("Bienvenido al programa\n");
}
Ahora desde dentro del cuerpo de nuestro programa, podríamos “llamar” a esa función:
main() {
saludar();
…
}
Así conseguimos que nuestro programa sea más fácil de leer. Como ejemplo, la parte principal de nuestra agenda podría ser simplemente:
leerDatosDeFichero();
do {
mostrarMenu();
pedirOpcion();
switch( opcion ) {
case 1: buscarDatos(); break;
case 2: modificarDatos(); break;
case 3: anadirDatos(); break;
…
7.3. Parámetros de una función
Es muy frecuente que nos interese además indicarle a nuestra función ciertos datos especiales con los que queremos que trabaje. Por ejemplo, si escribimos en pantalla números reales con frecuencia, nos puede resultar útil que nos los muestre con el formato que nos interese. Lo podríamos hacer así:
escribeNumeroReal( float n ) {
printf("%4.2f", n);
}
Y esta función se podría usar desde el cuerpo de nuestro programa así:
float x;
main() {
x= 5.1;
printf("El primer numero real es: ");
escribeNumeroReal(x);
printf(" y otro distinto es: ");
escribeNumeroReal(2.3);
}
Estos datos adicionales que indicamos a la función es lo que llamaremos sus “parámetros”. Como se ve en el ejemplo, tenemos que indicar un nombre para cada parámetro (puede haber varios) y el tipo de datos que corresponde a ese parámetro. Si hay más de un parámetro, deberemos indicar el tipo y el nombre para cada uno de ellos:
sumar ( int x, int y ) {
...
}
7.4. Valor devuelto por una función
También es habitual que queramos que nuestra función realice una serie de cálculos y nos “devuelva” el resultado de esos cálculos, para poderlo usar desde cualquier otra parte de nuestro programa. Por ejemplo, podríamos crear una función para elevar un número entero al cuadrado así:
int cuadrado ( int n ) {
return n*n;
}
main() {
int numero;
int resultado;
numero= 5;
resultado = cuadrado(numero);
printf("El cuadrado del numero es %d", resultado);
printf(" y el de 3 es %d", cuadrado(3));
}
Podemos hacer una función que nos diga cual es el mayor de dos números reales así:
float mayor ( float n1, float n2 ) {
if (n1>n2)
return n1;
else
return n2;
}
Ejercicios propuestos:
- Crear una función que borre la pantalla dibujando 25 líneas en blanco. No debe devolver ningún valor.
- Crear una función que calcule el cubo de un número real (float). El resultado deberá ser otro número real. Probar esta función para calcular el cubo de 3.2 y el de 5.
- Crear una función que calcule cual es el menor de dos números enteros. El resultado será otro número entero.
- Crear una función llamada “signo”, que reciba un número real, y devuelva un número entero con el valor: -1 si el número es negativo, 1 si es positivo o 0 si es cero.
- Crear una función que devuelva la primera letra de una cadena de texto. Probar esta función para calcular la primera letra de la frase “Hola”
- Crear una función que devuelva la última letra de una cadena de texto. Probar esta función para calcular la última letra de la frase “Hola”.
7.5. El valor de retorno “void”. El valor de retorno de “main”
Cuando queremos dejar claro que una función no tiene que devolver ningún valor, podemos hacerlo indicando al principio que el tipo de datos va a ser “void” (nulo). Por ejemplo, nuestra función “saludar”, que se limitaba a escribir varios textos en pantalla, quedaría más correcta si fuera así:
void saludar() {
printf("Bienvenido al programa\n");
printf(" de ejemplo\n");
printf("Bienvenido al programa\n");
}
Hay que tener en cuenta que si no indicamos tipo de datos, el lenguaje C no supondrá que no vaya a devolver ningún valor, sino que devolverá un valor entero (int). De hecho, la forma habitual de declarar el cuerpo de un programa (“main”) sería ésta, que es equivalente a la que hemos estado usando:
int main() {
...
}
Eso quiere decir que “main” también puede devolver un valor, que se leerá desde fuera de nuestro programa. Lo habitual es devolver 0 si todo ha funcionado correctamente
int main() {
...
return 0;
}
Y devolveríamos otro valor si hubiera habido algún problema durante el funcionamiento de nuestro programa (por ejemplo, si no hemos podido abrir algún fichero):
int main() {
FILE* fichero;
fichero = fopen("nombre.txt", "rt");
if (fichero == NULL) return 1;
...
return 0;
}
Este valor se podría comprobar desde el sistema operativo. Por ejemplo, en MsDos y Windows se lee con “IF ERRORLEVEL”, así:
IF ERRORLEVEL 1 ECHO Ha habido un error en el programa
Nota: En algunos lenguajes de programación se llama “procedimientos” (en inglés “procedure”) o “subrutinas” a las funciones que no devuelven ningún valor, y se reserva el nombre “función” para las que sí dan un resultado.
Ejercicios propuestos:
- Crear una función que borre la pantalla dibujando 25 líneas en blanco. No debe devolver ningún valor.
- Crear una función que reciba un número y muestre en pantalla el perímetro y la superficie de un cuadrado que tenga como lado el número que se ha indicado como parámetro.
7.6. Variables locales y variables globales
Hasta ahora, hemos declarado las variables antes de “main”. Ahora nuestros programas tienen varios “bloques”, así que se comportarán de forma distinta según donde declaremos las variables.
Las variables se pueden declarar dentro de un bloque (una función), y entonces sólo ese bloque las conocerá, no se podrán usar desde ningún otro bloque del programa. Es lo que llamaremos “variables locales”.
Por el contrario, si declaramos una variable al comienzo del programa, fuera de todos los “bloques” de programa, será una “variable global”, a la que se podrá acceder desde cualquier parte.
Vamos a verlo con un ejemplo. Crearemos una función que calcule la potencia de un número entero (un número elevado a otro), y el cuerpo del programa que la use.
La forma de conseguir elevar un número a otro será a base de multiplicaciones, es decir:
3 elevado a 5 = 3 · 3 · 3 · 3 · 3
(multiplicamos 5 veces el 3 por sí mismo). En general, como nos pueden pedir cosas como "6 elevado a 100" (o en general números que pueden ser grandes), usaremos la orden "for" para multiplicar tantas veces como haga falta:
/*---------------------------*/ /* Ejemplo en C nº 63: */ /* C063.C */ /* */ /* Ejemplo de función con */ /* variables locales */ /* */ /* Curso de C, */ /* Nacho Cabanes */ /*---------------------------*/ #include <stdio.h> int potencia(int base, int exponente) { int temporal = 1; /* Valor que voy hallando */ int i; /* Para bucles */ for(i=1; i<=exponente; i++) /* Multiplico "n" veces */ temporal *= base; /* Y calculo el valor temporal */ return temporal; /* Tras las multiplicaciones, */ } /* obtengo el valor que buscaba */ main() { int num1, num2; printf("Introduzca la base: "); scanf("%d", &num1); printf("Introduzca el exponente: "); scanf("%d", &num2); printf("%d elevado a %d vale %d", num1, num2, potencia(num1,num2)); }
En este caso, las variables “temporal” e “i” son locales a la función “potencia”: para “main” no existen. Si en “main” intentáramos hacer i=5; obtendríamos un mensaje de error.
De igual modo, “num1” y “num2” son locales para “main”: desde la función “potencia” no podemos acceder a su valor (ni para leerlo ni para modificarlo), sólo desde “main”.
En general, deberemos intentar que la mayor cantidad de variables posible sean locales (lo ideal sería que todas lo fueran). Así hacemos que cada parte del programa trabaje con sus propios datos, y ayudamos a evitar que un error en un trozo de programa pueda afectar al resto. La forma correcta de pasar datos entre distintos trozos de programa es usando los parámetros de cada función, como en el anterior ejemplo.
Ejercicios propuestos :
- Crear una función “pedirEntero”, que reciba como parámetros el texto que se debe mostrar en pantalla, el valor mínimo aceptable y el valor máximo aceptable. Deberá pedir al usuario que introduzca el valor tantas veces como sea necesario, volvérselo a pedir en caso de error, y devolver un valor correcto. Probarlo con un programa que pida al usuario un año entre 1800 y 2100.
- Crear una función “escribirTablaMultiplicar”, que reciba como parámetro un número entero, y escriba la tabla de multiplicar de ese número (por ejemplo, para el 3 deberá llegar desde 3x0=0 hasta 3x10=30).
- Crear una función “esPrimo”, que reciba un número y devuelva el valor 1 si es un número primo o 0 en caso contrario.
- Crear una función que reciba una cadena y una letra, y devuelva la cantidad de veces que dicha letra aparece en la cadena. Por ejemplo, si la cadena es "Barcelona" y la letra es 'a', debería devolver 2 (aparece 2 veces).
- Crear una función que reciba un número cualquiera y que devuelva como resultado la suma de sus dígitos. Por ejemplo, si el número fuera 123 la suma sería 6.
- Crear una función que reciba una letra y un número, y escriba un “triángulo” formado por esa letra, que tenga como anchura inicial la que se ha indicado. Por ejemplo, si la letra es * y la anchura es 4, debería escribir
****
***
**
*
7.7. Los conflictos de nombres en las variables
¿Qué ocurre si damos el mismo nombre a dos variables locales? Vamos a comprobarlo con un ejemplo:
/*---------------------------*/ /* Ejemplo en C nº 64: */ /* C064.C */ /* */ /* Dos variables locales */ /* con el mismo nombre */ /* */ /* Curso de C, */ /* Nacho Cabanes */ /*---------------------------*/ #include <stdio.h> void duplica(int n) { n = n * 2; } main() { int n = 5; printf("n vale %d\n", n); duplica(n); printf("Ahora n vale %d\n", n); }
El resultado de este programa es:
n vale 5
Ahora n vale 5
¿Por qué? Sencillo: tenemos una variable local dentro de “duplica” y otra dentro de “main”. El hecho de que las dos tengan el mismo nombre no afecta al funcionamiento del programa, siguen siendo distintas. El programa se comporta como si “duplica” fuera así:
void duplica(int x) {
x = x * 2;
}
es decir, como si ambas tuvieran nombres distintos.
¿Y qué ocurre si una de ellas es una variable global? Retoquemos el ejemplo:
/*---------------------------*/ /* Ejemplo en C nº 65: */ /* C065.C */ /* */ /* Variables locales y */ /* globales con el mismo */ /* nombre */ /* */ /* Curso de C, */ /* Nacho Cabanes */ /*---------------------------*/ #include <stdio.h> int n = 5; void duplica(int n) { n = n * 2; } main() { printf("n vale %d\n", n); duplica(n); printf("Ahora n vale %d\n", n); }
El resultado será exactamente el mismo: la línea “void duplica(int n)” hace que dentro de “duplica”, n se comporte como una variable local, por lo que los cambios que le hagamos no afectan a la variable global.
¿Y si queremos que se pueda modificar un dato indicado como parámetro? Todavía no sabemos como hacerlo (lo veremos en el próximo tema). Por ahora sólo sabemos hacerlo devolviendo el nuevo valor con “return”, con lo que nuestro último ejemplo quedaría así:
/*---------------------------*/ /* Ejemplo en C nº 66: */ /* C066.C */ /* */ /* Modificar la variable */ /* indicada como parámetro: */ /* devolviendo su valor */ /* */ /* Curso de C, */ /* Nacho Cabanes */ /*---------------------------*/ #include <stdio.h> int duplica(int n) { return n * 2; } main() { int n = 5; printf("n vale %d\n", n); n = duplica(n); printf("Ahora n vale %d\n", n); }
7.8. El orden importa
En general, una función debe estar declarada antes de usarse. Por ejemplo, este fuente daría un error en muchos compiladores, porque dentro de “main” intentamos usar algo llamado “duplica”, que no se ha mencionado antes:
/*---------------------------*/ /* Ejemplo en C nº 67: */ /* C067.C */ /* */ /* Función desordenada: */ /* puede no compilar */ /* */ /* Curso de C, */ /* Nacho Cabanes */ /*---------------------------*/ #include <stdio.h> main() { float n = 5; printf("n vale %f\n", n); n = duplica(n); printf("Ahora n vale %f\n", n); } float duplica(float n) { return n * 2; }
La forma de evitarlo es colocar la definición de las funciones antes de usarlas (si se puede) o bien incluir al menos su “prototipo”, la cabecera de la función sin incluir los detalles de cómo trabaja internamente, así:
/*---------------------------*/ /* Ejemplo en C nº 68: */ /* C068.C */ /* */ /* Prototipo de la función */ /* antes de main para que */ /* compile sin problemas */ /* */ /* Curso de C, */ /* Nacho Cabanes */ /*---------------------------*/ #include <stdio.h> float duplica(float n) ; main() { float n = 5; printf("n vale %f\n", n); n = duplica(n); printf("Ahora n vale %f\n", n); } float duplica(float n) { return n * 2; }
Como curiosidad, si no declaramos la función ni su prototipo antes de “main”, más de un compilador dará por sentado que es “int”, de modo que este otro fuente sí compilaría correctamente en la mayoría de sistemas:
main() {
int n = 5;
printf("n vale %d\n", n);
n = duplica(n);
printf("Ahora n vale %d\n", n);
}
int duplica(int n) {
return n * 2;
}
7.9. Algunas funciones útiles
7.9.1. Números aleatorios
En un programa de gestión o una utilidad que nos ayuda a administrar un sistema, no es habitual que podamos permitir que las cosas ocurran al azar. Pero los juegos se encuentran muchas veces entre los ejercicios de programación más completos, y para un juego sí suele ser conveniente que haya algo de azar, para que una partida no sea exactamente igual a la anterior.
Generar números al azar (“números aleatorios”) usando C no es difícil. Si nos ceñimos al estándar ANSI C, tenemos una función llamada “rand()”, que nos devuelve un número entero entre 0 y el valor más alto que pueda tener un número entero en nuestro sistema. Generalmente, nos interesarán números mucho más pequeños (por ejemplo, del 1 al 100), por lo que “recortaremos” usando la operación módulo (“%”, el resto de la división).
Vamos a verlo con algún ejemplo:
Para obtener un número del 0 al 9 haríamos x = rand() % 10;
Para obtener un número del 0 al 29 haríamos x = rand() % 30;
Para obtener un número del 10 al 29 haríamos x = rand() % 20 + 10;
Para obtener un número del 1 al 100 haríamos x = rand() % 100 + 1;
Para obtener un número del 50 al 60 haríamos x = rand() % 11 + 50;
Para obtener un número del 101 al 199 haríamos x = rand() % 100 + 101;
Pero todavía nos queda un detalle para que los números aleatorios que obtengamos sean “razonables”: los números que genera un ordenador no son realmente al azar, sino “pseudo-aleatorios”, cada uno calculado a partir del siguiente. Podemos elegir cual queremos que sea el primer número de esa serie (la “semilla”), pero si usamos uno prefijado, los números que se generarán serán siempre los mismos. Por eso, será conveniente que el primer número se base en el reloj interno del ordenador: como es casi imposible que el programa se ponga en marcha dos días exactamente a la misma hora (incluyendo milésimas de segundo), la serie de números al azar que obtengamos será distinta cada vez.
La “semilla” la indicamos con “srand”, y si queremos basarnos en el reloj interno del ordenador, lo que haremos será srand(time(0)); antes de hacer ninguna llamada a “rand()”.
Para usar “rand()” y “srand()”, deberíamos añadir otro fichero a nuestra lista de “includes”, el llamado “stdlib”:
#include <stdlib.h>
Si además queremos que la semilla se tome a partir del reloj interno del ordenador (que es lo más razonable), deberemos incluir también “time”:
#include <time.h>
Vamos a ver un ejemplo, que muestre en pantalla un número al azar entre 1 y 10:
/*---------------------------*/ /* Ejemplo en C nº 69: */ /* C069.C */ /* */ /* Obtener un número al */ /* azar */ /* */ /* Curso de C, */ /* Nacho Cabanes */ /*---------------------------*/ #include <stdio.h> #include <stdlib.h> #include <time.h> main() { int n; srand(time(0)); n = rand() % 10 + 1; printf("Un número entre 1 y 10: %d\n", n); }
Ejercicios propuestos:
* Crear un programa que genere un número al azar entre 1 y 100. El usuario tendrá 6 oportunidades para acertarlo.
7.9.2. Funciones matemáticas
Dentro del fichero de cabecera “math.h” tenemos acceso a muchas funciones matemáticas predefinidas en C, como:
- acos(x): Arco coseno
- asin(x): Arco seno$
- atan(x): Arco tangente
- atan2(y,x): Arco tangente de y/x (por si x o y son 0)
- ceil(x): El valor entero superior a x y más cercano a él
- cos(x): Coseno
- cosh(x): Coseno hiperbólico
- exp(x): Exponencial de x (e elevado a x)
- fabs(x): Valor absoluto
- floor(x): El mayor valor entero que es menor que x
- fmod(x,y): Resto de la división x/y
- log(x): Logaritmo natural (o neperiano, en base “e”)
- log10(x): Logaritmo en base 10
- pow(x,y): x elevado a y
- sin(x): Seno
- sinh(x): Seno hiperbólico
- sqrt(x): Raíz cuadrada
- tan(x): Tangente
- tanh(x): Tangente hiperbólica
(todos ellos usan parámetros X e Y de tipo “double”)
y una serie de constantes como
M_E, el número “e”, con un valor de 2.71828...
M_PI, el número “Pi”, 3.14159...
La mayoría de ellas son específicas para ciertos problemas matemáticos, especialmente si interviene la trigonometría o si hay que usar logaritmos o exponenciales. Pero vamos a destacar las que sí pueden resultar útiles en situaciones más variadas:
La raiz cuadrada de 4 se calcularía haciendo x = sqrt(4);
La potencia: para elevar 2 al cubo haríamos y = pow(2, 3);
El valor absoluto: si queremos trabajar sólo con números positivos usaríamos n = fabs(x);
Ejercicios propuestos:
- Crear un programa que halle cualquier raíz de un número. El usuario deberá indicar el número (por ejemplo, 2) y el índice de la raiz (por ejemplo, 3 para la raíz cúbica). Pista: hallar la raíz cúbica de 2 es lo mismo que elevar 2 a 1/3.
- Crear un programa que resuelva ecuaciones de segundo grado, del tipo ax2 + bx + c = 0 El usuario deberá introducir los valores de a, b y c. Pista: la solución se calcula con
x = ? raíz (b2 – 4·a·c) / 2·a
7.9.3. Pero casi todo son funciones…
Pero en C hay muchas más funciones de lo que parece. De hecho, casi todo lo que hasta ahora hemos llamado “órdenes”, son realmente “funciones”, y la mayoría de ellas incluso devuelven algún valor, que hasta ahora habíamos despreciado en muchos casos.
Vamos a hacer un repaso rápido a las funciones que ya conocemos y el valor que devuelven:
Función |
Valor devuelto |
Significado |
main |
int |
Programa terminado correctamente (0) o no (otro) |
printf |
int |
Número de caracteres escritos |
scanf |
int |
Número de datos leídos, o EOF si hay error |
putchar |
int |
El carácter escrito, o EOF si hay algún error |
getchar |
int |
Siguiente carácter de la entrada, o EOF en caso de error |
gets |
char* |
Cadena si todo va bien o NULL si hay error |
puts |
int |
EOF si hay algún error, otro número (un entero positivo) si no lo hay |
strcpy, strncpy |
char* |
Cadena resultado de la asignación |
strcat |
char* |
Cadena resultado |
strcmp |
int |
0 si las cadenas son iguales, <0 si la primera “es menor” o >0 si la primera “es mayor” |
sprintf |
int |
Número de caracteres almacenados en la cadena (en alguna versión, como BSD, devuelve la cadena creada) |
sscanf |
int |
Número de datos leídos, o EOF si hay error |
fopen |
FILE* |
NULL si hay error |
fclose |
int |
0 si todo va bien o EOF si hay error |
fputs |
int |
EOF si hay algún error, otro número (no especificado) si no lo hay |
fgets |
char* |
NULL si hay error o fin de fichero |
feof |
int |
0 si no es final de fichero, otro valor si lo es |
fprintf |
int |
Número de bytes escritos (puede no ser fiable si se está escribiendo a un buffer antes de mandar a disco). |
fscanf |
int |
Número de datos leídos, o EOF si hay error |
fgetc |
int |
El carácter leido, o EOF si hay algún error |
fputc |
int |
El carácter escrito, o EOF si hay algún error |
fread |
int |
Número de bytes leidos (0 o menor de lo previsto si hay error) |
fwrite |
int |
Número de bytes escritos (0 o menor de lo previsto si hay error) |
fseek |
int |
0 si se ha saltado correctamente; otro valor si el fichero no está abierto o no se ha podido saltar |
ftell |
long (size_t) |
Posición actual en el fichero (en bytes) o -1L en caso de error |
(Nota: expresiones como “FILE*” ya las conocemos, aunque todavía no entendemos bien a qué se refieren: otras como “char*” son nuevas para nosotros, pero las veremos con detalle en el próximo tema).
Por el contrario, las siguientes “órdenes” no son funciones, sino “palabras reservadas” del lenguaje C: if, else, do, while, for, switch, case, default, break, int, char, float, double, struct.
7.10. Recursividad
Una función recursiva es aquella que se define a partir de ella misma. Dentro de las matemáticas tenemos varios ejemplos. Uno clásico es el "factorial de un número":
n! = n · (n-1) · (n-2) · ... · 3 · 2 · 1
(por ejemplo, el factorial de 4 es 4 · 3 · 2 · 1 = 24)
Si pensamos que el factorial de n-1 es
(n-1)! = (n-1) · (n-2) · (n-3) · ... · 3 · 2 · 1
Entonces podemos escribir el factorial de un número a partir del factorial del siguiente número:
n! = n · (n-1)!
Esta es la definición recursiva del factorial, ni más ni menos. Esto, programando, se haría:
/*---------------------------*/ /* Ejemplo en C nº 70: */ /* C070.C */ /* */ /* Funciones recursivas: */ /* factorial */ /* */ /* Curso de C, */ /* Nacho Cabanes */ /*---------------------------*/ #include <stdio.h> long fact(int n) { if (n==1) /* Aseguramos que termine */ return 1; return n * fact (n-1); /* Si no es 1, sigue la recursión */ } main() { int num; printf("Introduzca un número entero: "); scanf("%d", &num); printf("Su factorial es: %ld\n", fact(num)); }
Dos consideraciones importantes:
- Atención a la primera parte de la función recursiva: es MUY IMPORTANTE comprobar que hay salida de la función, para que nuestro programa no se quede dando vueltas todo el tiempo y deje el ordenador (o la tarea actual) “colgado”.
- Los factoriales crecen rápidamente, así que no conviene poner números grandes: el factorial de 16 es 2.004.189.184, luego a partir de 17 podemos obtener resultados erróneos, según sea el tamaño de los números enteros en nuestro sistema.
¿Qué utilidad tiene esto? Pues más de la que parece: muchos problemas complicados se pueden expresar a partir de otro más sencillo. En muchos de esos casos, ese problema se podrá expresar de forma recursiva. Más adelante veremos algún otro ejemplo.
Ejercicios propuestos:
- Crear una función que calcule el valor de elevar un número entero a otro número entero (por ejemplo, 5 elevado a 3 = 53 = 5 ·5 · 3 = 125). Esta función se debe crear de forma recursiva.
- Como alternativa, crear una función que calcule el valor de elevar un número entero a otro número entero de forma NO recursiva (lo que llamaremos “de forma iterativa”), usando la orden “for”.
- Crear un programa que emplee recursividad para calcular un número de la serie Fibonacci (en la que los dos primeros elementos valen 1, y para los restantes, cada elemento es la suma de los dos anteriores).
- Crear un programa que emplee recursividad para calcular la suma de los elementos de un vector.
- Crear un programa que emplee recursividad para calcular el mayor de los elementos de un vector.
- Crear un programa que emplee recursividad para dar la vuelta a una cadena de caracteres (por ejemplo, a partir de "Hola" devolvería "aloH").
- Crear, tanto de forma recursiva como de forma iterativa, una función diga si una cadena de caracteres es simétrica (un palíndromo). Por ejemplo, "DABALEARROZALAZORRAELABAD" es un palíndromo.
- Crear un programa que encuentre el máximo común divisor de dos números usando el algoritmo de Euclides : Dados dos números enteros positivos m y n, tal que m > n, para encontrar su máximo común divisor, es decir, el mayor entero positivo que divide a ambos: - Dividir m por n para obtener el resto r (0 = r < n) ; - Si r = 0, el MCD es n.; - Si no, el máximo común divisor es MCD(n,r).
7.11. Cómo interrumpir el programa.
Si queremos que nuestro programa se interrumpa en un cierto punto, podemos usar la orden “exit”, que ya habíamos utilizado en el apartado 6.2, cuando vimos si podíamos abrir un fichero sin errores.
Su manejo habitual es algo como
exit(1);
Es decir, entre paréntesis indicamos un cierto código, que suele ser (por convenio) un 0 si no ha habido ningún error, u otro código distinto en caso de que sí exista algún error, al igual que vimos con el valor de retorno de “main” (y el uso de este código es el que vimos entonces).
Si queremos utilizar “exit”, deberíamos añadir otro fichero a nuestra lista de “includes”, el llamado “stdlib”:
#include <stdlib.h>
(Aun así, al igual que ocurría con “stdio.h”, algunos compiladores permitirán que nuestro programa funcione correctamente aunque no tenga esta línea).
Igualmente, al final de nuestro programa, lo correcto sería devolver el valor 0 si no ha habido ningún error:
int main() {
...
return 0;
}