dividir un programa en piezas reutilizables y entender cómo viven las variables.
Incluye 4 ejercicios con pistas y solución y un quiz de 5 preguntas. Tiempo estimado: 70 minutos.
1. Definir y llamar
tipo_devuelto nombre(tipo param1, tipo param2) {
...
return valor;
}
int cuadrado(int x) {
return x * x;
}
int main(void) {
printf("%d\n", cuadrado(7)); // 49
return 0;
}
voidcomo tipo de retorno = no devuelve nada.voidcomo lista de parámetros = no recibe nada.- Una función hace una cosa y tiene un nombre que la describe (
es_primo, nof2).
2. Prototipos
El compilador lee de arriba abajo: una función debe conocerse antes de usarse. Dos soluciones: definirla antes de main, o declarar su prototipo:
int cuadrado(int x); // prototipo: solo la firma + ;
int main(void) { ... cuadrado(3) ... }
int cuadrado(int x) { return x * x; }
Los prototipos son justo lo que irá a los ficheros .h (módulo 11).
3. Paso por valor
En C los argumentos se copian:
void incrementa(int n) { n++; } // modifica SU copia
int x = 5;
incrementa(x); // x sigue valiendo 5
Para modificar el original se pasa su dirección (punteros, módulo 7). Los arrays sí "se modifican" porque lo que se copia es la dirección del primer elemento.
4. Ámbito y vida de las variables
| Clase | Dónde | Vive | Visible |
|---|---|---|---|
| Local | dentro de una función/bloque | mientras dura la llamada | solo ahí |
| Global | fuera de funciones | todo el programa | en todo el fichero |
static local |
dentro de función | todo el programa | solo ahí (conserva valor entre llamadas) |
Evita las globales: hacen el código difícil de razonar. Pasa datos por parámetros.
5. Recursión
Una función que se llama a sí misma. Necesita: 1. Caso base: donde para. 2. Paso recursivo: reduce el problema hacia el caso base.
long long factorial(int n) {
if (n <= 1) return 1; // caso base
return n * factorial(n - 1); // paso recursivo
}
Cada llamada ocupa memoria en la pila (stack). Sin caso base, se agota → stack overflow.
Ojo: fib(n-1) + fib(n-2) recalcula lo mismo muchísimas veces (exponencial). fib(40) ya tarda; aprenderás a evitarlo con bucles o memoización.
Cuándo recursión vs. bucle: la recursión brilla en estructuras que se auto-contienen (árboles, listas); para cosas lineales, un bucle suele ser más claro y barato.
6. Buenas prácticas
- Funciones cortas (idealmente < 30 líneas).
- Evita efectos laterales sorprendentes: si imprime, que se llame
imprimir_.... - Comprueba entradas inválidas (¿qué hace tu
factorial(-3)?).
Prueba esto
- Escribe
int max3(int a, int b, int c)reutilizando unamax2. - Una función
static int contador()que devuelva 1, 2, 3... en llamadas sucesivas. - Quita el caso base de
factorialy ejecútalo (verás un crash controlado).
Ejercicios prácticos del módulo 5
Programar se aprende programando: intenta cada ejercicio antes de mirar las pistas, y usa la solución solo para comparar. Marca los que resuelvas y tu progreso se guarda en este navegador.
5.1 Potencia entera
Entrada de ejemplo
2 10
Salida esperada
1024
Tu punto de partida
#include <stdio.h>
long long potencia(int base, int exp) {
// TODO
return 0;
}
int main(void) {
int b, e;
scanf("%d %d", &b, &e);
printf("%lld\n", potencia(b, e));
return 0;
}Cópialo en tu editor, complétalo, compílalo (gcc -Wall -Wextra programa.c -o programa) y prueba la entrada de ejemplo. Para que se corrija solo con varios casos de prueba, descarga el curso.
Pista 1
Empieza con r = 1 y multiplica por base, exp veces.
Pista 2
Si exp es 0 el resultado es 1: el bucle no se ejecuta y r ya vale 1.
Ver solución (inténtalo antes)
#include <stdio.h>
long long potencia(int base, int exp) {
long long r = 1;
for (int i = 0; i < exp; i++) r *= base;
return r;
}
int main(void) {
int b, e;
scanf("%d %d", &b, &e);
printf("%lld\n", potencia(b, e));
return 0;
}5.2 Funcion es_primo
Entrada de ejemplo
6 1 2 9 13 25 97
Salida esperada
1 no primo 2 primo 9 no primo 13 primo 25 no primo 97 primo
Tu punto de partida
#include <stdio.h>
int es_primo(int n) {
// TODO
return 0;
}
int main(void) {
int cuantos, x;
scanf("%d", &cuantos);
for (int i = 0; i < cuantos; i++) {
scanf("%d", &x);
printf("%d %s\n", x, es_primo(x) ? "primo" : "no primo");
}
return 0;
}Cópialo en tu editor, complétalo, compílalo (gcc -Wall -Wextra programa.c -o programa) y prueba la entrada de ejemplo. Para que se corrija solo con varios casos de prueba, descarga el curso.
Pista 1
Casos especiales: n < 2 no es primo.
Pista 2
Un return dentro del bucle sale de la funcion en cuanto encuentra divisor.
Ver solución (inténtalo antes)
#include <stdio.h>
int es_primo(int n) {
if (n < 2) return 0;
for (int d = 2; d * d <= n; d++)
if (n % d == 0) return 0;
return 1;
}
int main(void) {
int cuantos, x;
scanf("%d", &cuantos);
for (int i = 0; i < cuantos; i++) {
scanf("%d", &x);
printf("%d %s\n", x, es_primo(x) ? "primo" : "no primo");
}
return 0;
}5.3 Recursion: factorial y Fibonacci
Entrada de ejemplo
0
Salida esperada
factorial(0)=1 fib(0)=0
Tu punto de partida
#include <stdio.h>
long long factorial(int n) {
// TODO: caso base + llamada recursiva
return 0;
}
long long fib(int n) {
// TODO
return 0;
}
int main(void) {
int n;
scanf("%d", &n);
printf("factorial(%d)=%lld\n", n, factorial(n));
printf("fib(%d)=%lld\n", n, fib(n));
return 0;
}Cópialo en tu editor, complétalo, compílalo (gcc -Wall -Wextra programa.c -o programa) y prueba la entrada de ejemplo. Para que se corrija solo con varios casos de prueba, descarga el curso.
Pista 1
Toda recursion necesita un CASO BASE que no se llame a si mismo.
Pista 2
factorial: si n <= 1 devuelve 1, si no n * factorial(n-1).
Pista 3
fib: si n < 2 devuelve n, si no fib(n-1) + fib(n-2).
Ver solución (inténtalo antes)
#include <stdio.h>
long long factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
long long fib(int n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2);
}
int main(void) {
int n;
scanf("%d", &n);
printf("factorial(%d)=%lld\n", n, factorial(n));
printf("fib(%d)=%lld\n", n, fib(n));
return 0;
}5.4 MCD y MCM (Euclides)
Entrada de ejemplo
12 18
Salida esperada
mcd=6 mcm=36
Tu punto de partida
#include <stdio.h>
int mcd(int a, int b) {
// TODO
return 0;
}
long long mcm(int a, int b) {
// TODO: usa mcd
return 0;
}
int main(void) {
int a, b;
scanf("%d %d", &a, &b);
printf("mcd=%d mcm=%lld\n", mcd(a, b), mcm(a, b));
return 0;
}Cópialo en tu editor, complétalo, compílalo (gcc -Wall -Wextra programa.c -o programa) y prueba la entrada de ejemplo. Para que se corrija solo con varios casos de prueba, descarga el curso.
Pista 1
Euclides: mientras b != 0, sustituye (a, b) por (b, a % b). El resultado es a.
Pista 2
mcm = a / mcd * b (divide antes de multiplicar para evitar desbordar).
Ver solución (inténtalo antes)
#include <stdio.h>
int mcd(int a, int b) {
while (b != 0) {
int t = a % b;
a = b;
b = t;
}
return a;
}
long long mcm(int a, int b) {
return (long long)a / mcd(a, b) * b;
}
int main(void) {
int a, b;
scanf("%d %d", &a, &b);
printf("mcd=%d mcm=%lld\n", mcd(a, b), mcm(a, b));
return 0;
}Quiz del módulo 5
5 preguntas para comprobar que has fijado los conceptos. Las opciones se barajan cada vez.