Curso de C · Módulo 5 de 12

Funciones y recursión en C

Qué aprenderás en este módulo

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;
}
  • void como tipo de retorno = no devuelve nada. void como lista de parámetros = no recibe nada.
  • Una función hace una cosa y tiene un nombre que la describe (es_primo, no f2).

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

  1. Escribe int max3(int a, int b, int c) reutilizando una max2.
  2. Una función static int contador() que devuelva 1, 2, 3... en llamadas sucesivas.
  3. Quita el caso base de factorial y 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
El main ya esta escrito: lee base y exponente (>= 0) y llama a potencia(base, exp). Implementa la funcion long long potencia(int base, int exp) usando un bucle (sin pow()).

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
Implementa int es_primo(int n) que devuelva 1 si n es primo y 0 si no (n puede ser <= 1: no primo). El main imprime los primos de la lista de numeros que lee (primero la cantidad, luego los numeros).

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
Implementa RECURSIVAMENTE: long long factorial(int n) (factorial(0) = 1) long long fib(int n) (fib(0)=0, fib(1)=1, fib(n)=fib(n-1)+fib(n-2)) El main esta hecho. No uses bucles en las funciones.

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)
Implementa int mcd(int a, int b) con el algoritmo de Euclides (mcd(a,0)=a; mcd(a,b)=mcd(b, a%b)) y long long mcm(int a, int b) usando mcd. Entradas positivas.

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.