Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Ejercicios: Creación de Librerías de Funciones

Diseño, encapsulamiento e implementación de módulos reutilizables en C

Universidad Nacional de Río Negro

Prerrequisitos y Entorno de Ejecución Requerido

Para compilar y resolver los módulos de esta guía se requiere:

  1. Entorno de compilación: GCC 9+ o Clang con soporte estricto ISO C11 (-std=c11 -Wall -Wextra -Werror -pedantic) bajo Linux/POSIX.

  2. Dependencias del sistema: Biblioteca matemática de C (libm), enlazada explícitamente mediante el flag -lm.

  3. Conceptos previos de arquitectura de software:

    • Separación estricta entre cabecera pública (.h) e implementación privada (.c).

    • Guardas del preprocesador contra inclusión múltiple (#ifndef, #define, #endif).

    • Visibilidad interna y ocultamiento de símbolos auxiliares con el calificador static.

    • Comparación numérica con tolerancia épsilon (fabs(a - b) < 1e-6) para punto flotante.

Objetivos Pedagógicos y Competencias (Taxonomía de Bloom)

Acerca de

La creación de librerías de funciones (módulos reutilizables) permite estructurar programas de forma limpia, testeable y mantenible. Se recomienda la estructura canónica modular:


1. Librerías Matemáticas y Numéricas

Ejercicio 1.04b.01 - Librería de Operaciones Geométricas 2D ⭐⭐☆☆☆

```c #include <stdio.h> #include <math.h> #include <assert.h> #define EPSILON 1e-7 static int casi_igual(double a, double b) { return fabs(a - b) < EPSILON; } double geo_distancia(double x1, double y1, double x2, double y2) { double dx = x2 - x1; double dy = y2 - y1; return sqrt(dx * dx + dy * dy); } double geo_area_rectangulo(double ancho, double alto) { if (ancho < 0.0 || alto < 0.0) { return -1.0; } return ancho * alto; } double geo_perimetro_rectangulo(double ancho, double alto) { if (ancho < 0.0 || alto < 0.0) { return -1.0; } return 2.0 * (ancho + alto); } int main(void) { assert(casi_igual(geo_distancia(0.0, 0.0, 3.0, 4.0), 5.0)); assert(casi_igual(geo_distancia(1.0, 1.0, 1.0, 1.0), 0.0)); assert(casi_igual(geo_area_rectangulo(4.0, 5.0), 20.0)); assert(casi_igual(geo_perimetro_rectangulo(4.0, 5.0), 18.0)); /* Casos defensivos */ assert(casi_igual(geo_area_rectangulo(-1.0, 5.0), -1.0)); assert(casi_igual(geo_perimetro_rectangulo(4.0, -2.0), -1.0)); return 0; } ```

---

(ej_b1_c04b_02)=
### Ejercicio 1.04b.02 - Librería de Conversión de Unidades ⭐⭐☆☆☆

:::{exercise}
:label: ej_b1_c04b_02_conversiones

Creá un módulo de conversión de unidades termodinámicas y cinemáticas:
- `double conv_celsius_a_fahrenheit(double c)`
- `double conv_fahrenheit_a_celsius(double f)`
- `double conv_kmh_a_ms(double kmh)`
- `double conv_ms_a_kmh(double ms)`

**Tabla de Vectores de Prueba:**

| Magnitud | Entrada | Función Invocada | Resultado Esperado | Tolerancia |
| :--- | :--- | :--- | :--- | :--- |
| Temperatura | `0.0 °C` | `conv_celsius_a_fahrenheit` | `32.0 °F` | `1e-6` |
| Temperatura | `212.0 °F`| `conv_fahrenheit_a_celsius` | `100.0 °C` | `1e-6` |
| Velocidad | `36.0 km/h` | `conv_kmh_a_ms` | `10.0 m/s` | `1e-6` |
| Velocidad | `10.0 m/s` | `conv_ms_a_kmh` | `36.0 km/h` | `1e-6` |

::::{solution}
```c
#include <stdio.h>
#include <math.h>
#include <assert.h>

#define EPSILON 1e-6

static int casi_igual(double a, double b) {
    return fabs(a - b) < EPSILON;
}

double conv_celsius_a_fahrenheit(double c) {
    return (c * 9.0 / 5.0) + 32.0;
}

double conv_fahrenheit_a_celsius(double f) {
    return (f - 32.0) * 5.0 / 9.0;
}

double conv_kmh_a_ms(double kmh) {
    return kmh / 3.6;
}

double conv_ms_a_kmh(double ms) {
    return ms * 3.6;
}

int main(void) {
    assert(casi_igual(conv_celsius_a_fahrenheit(0.0), 32.0));
    assert(casi_igual(conv_celsius_a_fahrenheit(100.0), 212.0));
    assert(casi_igual(conv_fahrenheit_a_celsius(32.0), 0.0));
    assert(casi_igual(conv_fahrenheit_a_celsius(212.0), 100.0));

    assert(casi_igual(conv_kmh_a_ms(36.0), 10.0));
    assert(casi_igual(conv_ms_a_kmh(10.0), 36.0));

    return 0;
}
```

---

(ej_b1_c04b_03)=
### Ejercicio 1.04b.03 - Librería de Estadística Básica ⭐⭐⭐☆☆

:::{exercise}
:label: ej_b1_c04b_03_estadistica

Implementá un módulo para cálculo de estadísticas básicas sobre arreglos de punto flotante en C11:
- `double est_media(const double *datos, size_t n)`: retorna la media aritmética, o `0.0` si `n == 0` o `datos == NULL`.
- `double est_minimo(const double *datos, size_t n)`: retorna el valor mínimo del arreglo.
- `double est_maximo(const double *datos, size_t n)`: retorna el valor máximo del arreglo.

**Tabla de Vectores de Prueba:**

| Caso de Prueba | Arreglo de Datos | Función Invocada | Retorno Esperado |
| :--- | :--- | :--- | :--- |
| Muestra estándar | `[2.0, 4.0, 6.0]` | `est_media` | `4.0` |
| Rango extremos | `[10.5, -3.2, 8.0, 15.1]` | `est_minimo` / `est_maximo` | `-3.2` / `15.1` |
| Arreglo unitario | `[42.0]` | `est_media` | `42.0` |
| Puntero nulo | `NULL, 0` | `est_media` | `0.0` |

::::{solution}
```c
#include <stdio.h>
#include <stddef.h>
#include <math.h>
#include <assert.h>

#define EPSILON 1e-6

static int casi_igual(double a, double b) {
    return fabs(a - b) < EPSILON;
}

double est_media(const double *datos, size_t n) {
    if (datos == NULL || n == 0) {
        return 0.0;
    }
    double suma = 0.0;
    for (size_t i = 0; i < n; ++i) {
        suma += datos[i];
    }
    return suma / (double)n;
}

double est_minimo(const double *datos, size_t n) {
    if (datos == NULL || n == 0) {
        return 0.0;
    }
    double min = datos[0];
    for (size_t i = 1; i < n; ++i) {
        if (datos[i] < min) {
            min = datos[i];
        }
    }
    return min;
}

double est_maximo(const double *datos, size_t n) {
    if (datos == NULL || n == 0) {
        return 0.0;
    }
    double max = datos[0];
    for (size_t i = 1; i < n; ++i) {
        if (datos[i] > max) {
            max = datos[i];
        }
    }
    return max;
}

int main(void) {
    double m1[3] = {2.0, 4.0, 6.0};
    assert(casi_igual(est_media(m1, 3), 4.0));

    double m2[4] = {10.5, -3.2, 8.0, 15.1};
    assert(casi_igual(est_minimo(m2, 4), -3.2));
    assert(casi_igual(est_maximo(m2, 4), 15.1));

    double m3[1] = {42.0};
    assert(casi_igual(est_media(m3, 1), 42.0));

    assert(casi_igual(est_media(NULL, 0), 0.0));
    assert(casi_igual(est_minimo(NULL, 0), 0.0));
    assert(casi_igual(est_maximo(NULL, 0), 0.0));

    return 0;
}
```

(ej_b1_c04b_04)=
### Ejercicio 1.04b.04 - Librería de Números Primos y Factorización ⭐⭐⭐☆☆

:::{exercise}
:label: ej_b1_c04b_04_primos

Implementá una biblioteca para la verificación y generación de números primos con tipado estricto:
- `bool primo_es_primo(unsigned long n)`: retorna `true` si $n$ es primo ($n \ge 2$), `false` en caso contrario.
- `unsigned long primo_siguiente(unsigned long n)`: retorna el menor número primo estrictamente mayor que $n$.

**Tabla de Vectores de Prueba:**

| Caso de Prueba | Parámetro `n` | `primo_es_primo` | `primo_siguiente` |
| :--- | :--- | :--- | :--- |
| Primer primo | `2` | `true` | `3` |
| Número compuesto | `4` | `false` | `5` |
| Primo impar | `13` | `true` | `17` |
| Casos límite | `0`, `1` | `false` | `2` |

::::{solution}
```c
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>

bool primo_es_primo(unsigned long n) {
    if (n < 2) {
        return false;
    }
    if (n == 2 || n == 3) {
        return true;
    }
    if (n % 2 == 0 || n % 3 == 0) {
        return false;
    }
    for (unsigned long i = 5; i * i <= n; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) {
            return false;
        }
    }
    return true;
}

unsigned long primo_siguiente(unsigned long n) {
    if (n < 2) {
        return 2;
    }
    unsigned long candidato = n + 1;
    while (!primo_es_primo(candidato)) {
        candidato++;
    }
    return candidato;
}

int main(void) {
    assert(primo_es_primo(0) == false);
    assert(primo_es_primo(1) == false);
    assert(primo_es_primo(2) == true);
    assert(primo_es_primo(3) == true);
    assert(primo_es_primo(4) == false);
    assert(primo_es_primo(13) == true);
    assert(primo_es_primo(25) == false);

    assert(primo_siguiente(0) == 2);
    assert(primo_siguiente(1) == 2);
    assert(primo_siguiente(2) == 3);
    assert(primo_siguiente(4) == 5);
    assert(primo_siguiente(13) == 17);

    return 0;
}
```

---

(ej_b1_c04b_05)=
### Ejercicio 1.04b.05 - Librería de Trigonometría y Resolución de Triángulos ⭐⭐⭐☆☆

:::{exercise}
:label: ej_b1_c04b_05_trigonometria
:enumerator: librerias-5

Diseñá un módulo de cálculos geométricos y trigonométricos en C11 utilizando `<math.h>`:
```c
double trigo_hipotenusa(double cateto1, double cateto2);
double trigo_angulo_vector(double x, double y);
bool trigo_resolver_triangulo_sss(double a, double b, double c,
                                  double *alpha, double *beta, double *gamma);
```
- `trigo_hipotenusa`: Calcula $\sqrt{c_1^2 + c_2^2}$ utilizando `hypot` o la fórmula de Pitágoras.
- `trigo_angulo_vector`: Calcula el ángulo polar en radianes en el rango $[-\pi, \pi]$ mediante `atan2(y, x)`.
- `trigo_resolver_triangulo_sss`: Determina los tres ángulos interiores (en radianes) a partir de las longitudes de los lados $a, b, c$ usando el teorema del coseno:
  $$\cos(\alpha) = \frac{b^2 + c^2 - a^2}{2bc}$$
  Retorna `false` si los lados no cumplen la desigualdad triangular estricta ($a+b>c$, $a+c>b$, $b+c>a$) o si alguno de los punteros de salida es `NULL`.

**Nivel de Bloom:** Nivel 3 (Aplicación) y Nivel 4 (Análisis).  
**Conceptos requeridos:** Funciones de `<math.h>` (`hypot`, `atan2`, `acos`), validación de desigualdades geométricas, paso por referencia.  
**Techo conceptual:** Prohibido el uso de valores no numéricos (`NaN`) o divisiones por cero sin validación previa.

#### Contrato de las Funciones
- **Precondiciones:** Lados y catetos estrictamente positivos. Punteros de salida no nulos para `trigo_resolver_triangulo_sss`.
- **Postcondiciones:** Retorna `true` y escribe los ángulos cuya suma es exactamente $\pi$ radianes.

#### Tabla de Vectores de Prueba

| Triángulo ($a, b, c$) | Retorno | Ángulos ($\alpha, \beta, \gamma$) | Justificación Técnica |
| :--- | :--- | :--- | :--- |
| Equilátero ($2, 2, 2$) | `true` | $\pi/3, \pi/3, \pi/3$ | Tres ángulos iguales a $60^\circ$ |
| Rectángulo ($3, 4, 5$) | `true` | $\gamma = \pi/2$ | Hipotenusa opuesta al ángulo recto |
| Inválido ($1, 2, 10$) | `false` | Sin escrituras | Viola desigualdad triangular ($1 + 2 < 10$) |
| Puntero nulo | `false` | Sin escrituras | Rechazo defensivo |

2. Librerías de Manipulación de Texto y Cadenas

Ejercicio 1.04b.06 - Biblioteca de Strings seguros ⭐⭐⭐⭐⭐

Reimplementá funciones estándar de <string.h> en la librería seguras.h y seguras.c:

Orientación:


Ejercicio 1.04b.07 - Librería de Transformación de Cadenas In-Place ⭐⭐⭐☆☆


Ejercicio 1.04b.08 - Librería de Búsqueda y Conteo en Texto ⭐⭐⭐☆☆

Implementá la librería text_search.h y text_search.c:


Ejercicio 1.04b.09 - Librería de Formateo y Padding de Texto ⭐⭐⭐☆☆

Diseñá str_format.h y str_format.c:


Ejercicio 1.04b.10 - Librería de Sanitización e Inspección de Entradas ⭐⭐⭐☆☆

Creá sanitizer.h y sanitizer.c:


3. Librerías de Manejo de Arreglos y Matrices

Ejercicio 1.04b.11 - Librería de Vectores de Enteros ⭐⭐⭐☆☆


---

(ej_b1_c04b_12)=
### Ejercicio 1.04b.12 - Librería de Ordenamiento y Búsqueda ⭐⭐⭐⭐☆

Creá `sort_search.h` y `sort_search.c`:
- `void sort_burbuja(int *v, size_t n)`
- `void sort_seleccion(int *v, size_t n)`
- `void sort_insercion(int *v, size_t n)`
- `ssize_t busqueda_binaria(const int *v, size_t n, int elem)`

:::{hint} Lógica y Consideraciones
- Recordá que `busqueda_binaria` requiere que el arreglo esté previamente ordenado.

Ejercicio 1.04b.13 - Librería de Operaciones sobre Matrices 2D ⭐⭐⭐⭐☆

Diseñá matriz2d.h y matriz2d.c para matrices con dimensiones fijas o pasadas linealmente:


Ejercicio 1.04b.14 - Librería de Manipulación de Conjuntos sobre Arreglos ⭐⭐⭐⭐☆

Implementá conjunto_arr.h y conjunto_arr.c:


Ejercicio 1.04b.15 - Librería de Transformación y Filtrado de Arreglos ⭐⭐⭐⭐☆

Diseñá array_utils.h y array_utils.c para procesar secuencias numéricas mediante funciones modulares:


4. Librerías de Utilidades del Sistema y E/S

Ejercicio 1.04b.16 - Librería de Validación de Entradas de Usuario ⭐⭐☆☆☆

Diseñá input_val.h y input_val.c para simplificar la lectura segura desde stdin:


Ejercicio 1.04b.17 - Librería de Fechas y Calendario ⭐⭐⭐☆☆

Creá fechas.h y fechas.c:


Ejercicio 1.04b.18 - Librería de Consola y Formato de Salida ⭐⭐☆☆☆

Diseñá console_ui.h y console_ui.c:


Ejercicio 1.04b.19 - Librería de Medición de Tiempos de Ejecución ⭐⭐⭐☆☆

Implementá cronometro.h y cronometro.c:


Ejercicio 1.04b.20 - Librería de Generación Numérica Pseudoaleatoria ⭐⭐⭐☆☆

Creá azar.h y azar.c:


5. Librerías de Simulación y Dominios Específicos

Ejercicio 1.04b.21 - Librería de Física: Cinemática ⭐⭐☆☆☆

Diseñá fisica_cinematica.h y fisica_cinematica.c:


Ejercicio 1.04b.22 - Librería de Finanzas Básicas ⭐⭐☆☆☆

Creá finanzas.h y finanzas.c:


Ejercicio 1.04b.23 - Librería de Geometría 3D ⭐⭐⭐☆☆

Diseñá geometria3d.h y geometria3d.c:


Ejercicio 1.04b.24 - Librería de Conversión de Bases Numéricas ⭐⭐⭐☆☆

Implementá bases.h y bases.c:


Ejercicio 1.04b.25 - Librería de Criptografía Clásica ⭐⭐⭐☆☆

Diseñá cripto_simple.h y cripto_simple.c:


6. Librerías Avanzadas y Estructuración Compleja

Ejercicio 1.04b.26 - Librería de Manejo de Colores RGB ⭐⭐⭐☆☆

Creá color_utils.h y color_utils.c para cálculos de color mediante operaciones aritméticas y fórmulas estándar:


Ejercicio 1.04b.27 - Librería de Evaluación de Expresiones lógicas ⭐⭐⭐⭐☆

Diseñá eval_logica.h y eval_logica.c:


Ejercicio 1.04b.28 - Librería de Gestión de Estados y Banderas Booleanas ⭐⭐⭐⭐☆

Implementá flags.h y flags.c para gestionar conjuntos de opciones mediante arreglos booleanos:


Ejercicio 1.04b.29 - Librería de Manejo de Registro de Logs ⭐⭐⭐⭐☆

Diseñá logger.h y logger.c:


Ejercicio 1.04b.30 - Librería de Verificación de Integridad (Checksum) ⭐⭐⭐⭐⭐

Creá checksum.h y checksum.c:


Notas Finales