Repositorio Integral de Ejercicios de Programación 1¶
Este repositorio constituye la base pedagógica práctica de la asignatura Programación 1 (UNRN). Su diseño implementa un modelo de aprendizaje andamiado (scaffolded learning) y progresión gradual según la Taxonomía de Bloom Revisada, guiando al estudiante desde la sintaxis básica hasta la ingeniería de software y tipos abstractos en C11.
Requisitos Previos y Entorno de Ejecución¶
Compilador C: GCC (v9+) o Clang configurado en estándar estricto ISO C11 (
-std=c11 -Wall -Wextra -Werror -pedantic).Sistema y Dependencias: Entorno POSIX (Linux/macOS), utilidades
make, terminal Bash y Node.js (v18+) para verificación automática.Herramientas de Análisis: Valgrind y LLVM AddressSanitizer (
-fsanitize=address,undefined) para comprobación rigurosa de memoria.Conocimientos Previos: Aritmética elemental, álgebra booleana y manejo básico de la línea de comandos.
Enfoque Metodológico Formativo y Casos Límite¶
Cada ejercicio articula cuatro fases de dominio cognitivo:
Contratos Formales: Precondiciones, postcondiciones e invariantes explícitas.
Modularización Pura: Descomposición en funciones sin variables globales ni efectos colaterales.
Casos Borde y Manejo de Errores: Validación defensiva ante punteros
NULL, valores frontera (0,NULL, tamaños vacíos) y prevención estricta de división por cero o desbordamientos.Vectores de Prueba: Pruebas sistemáticas automatizadas en
main(void)con macroassert(...).Higiene de Memoria: Cero fugas en el Heap, verificación con sanitizers y ausencia de dobles liberaciones.
Flujo de Trabajo y Verificación Rápida¶
Compilación manual estricta:
gcc -Wall -Wextra -Werror -pedantic -std=c11 archivo.c -o programaVerificación estructural:
node ejercicios/verificar_calidad.mjsEjecución automatizada de soluciones:
node ejercicios/verificar_ejercicios.mjs
¿Y las prácticas?¶
Esta colección complementa las guías obligatorias de la cátedra para consolidar el aprendizaje autónomo mediante problemas graduados.
Consideraciones Generales¶
A seguir siempre y cuando no esté indicada otra cosa:
Resuelvan todos los ejercicios de manera iterativa, a no ser que esté indicado puntualmente.
Los números son números enteros, estos incluyen al cero y los negativos.
El nombre del archivo debe ser, el número del ejercicio reemplazando el punto por un guion y su apellido, por ejemplo:
1-1_apellido.c.Apliquen y completen la plantilla de resolución de ejercicios que está a continuación, copiando el título y consigna del ejercicio y luego completando con sus datos.
Lo que “resuelve” el enunciado debe estar encapsulado en una función, incluso si no está indicado explícitamente.
El código debe seguir estrictamente el catálogo de reglas de estilo de la cátedra.
Los ejercicios marcados como [plus ultra] son variaciones del ejercicio para ir «más allá» de la consigna original.
Plantilla de Archivo y Ejemplo de Referencia¶
Cada entrega individual debe estructurarse mediante funciones puras, modularización y un conjunto exhaustivo de pruebas en main(void). A continuación se presenta la plantilla estándar de resolución canónica (1-1_apellido.c):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36/* =============================================================================== Cátedra de Programación 1 - Universidad Nacional de Río Negro Ejercicio 1.01.01 - Ejemplo de Estructura Canónica Consigna: Implementar una función pura que valide si un entero es par. Autor: Alumno Ejemplo GitHub: @alumno-unrn =============================================================================== */ #include <assert.h> #include <stdbool.h> #include <stdio.h> /** * @brief Determina si un número entero es par. * @param n Número entero de entrada. * @return true si n es divisible por 2, false en caso contrario. */ bool es_par(int n) { return (n % 2 == 0); } int main(void) { /* Casos de prueba exhaustivos */ assert(es_par(0) == true); assert(es_par(2) == true); assert(es_par(-4) == true); assert(es_par(1) == false); assert(es_par(-7) == false); printf("Todos los vectores de prueba superados con éxito.\n"); return 0; }
Niveles de Dificultad¶
Todos los ejercicios se encuentran clasificados con la etiqueta
**Dificultad:** según su nivel de complejidad:
⭐☆☆☆☆ - Básico: Aplicación directa de 1-2 conceptos fundamentales.
⭐⭐☆☆☆ - Fácil: Combina 2-3 conceptos simples o estructuras elementales.
⭐⭐⭐☆☆ - Intermedio: Requiere diseño algorítmico o manejo de datos.
⭐⭐⭐⭐☆ - Avanzado: Múltiples conceptos integrados, indirección o optimización.
⭐⭐⭐⭐⭐ - Experto: Problemas complejos de arquitectura o algoritmos avanzados.
Consignas Plus Ultra¶
Cada ejercicio incluye consignas opcionales marcadas como [*plus ultra*]
(frase en latín que significa «más allá»). Estas consignas están diseñadas para
ir más allá de la consigna base y profundizar el aprendizaje mediante:
Validación y Casos de Borde: Manejo robusto de errores, valores límite y prevención de comportamientos indefinidos.
Optimización y Rendimiento: Mejora en el uso de memoria, tiempo de ejecución y eficiencia algorítmica.
Extensión y Abstracción: Generalización de soluciones, diseño de interfaces reutilizables o soporte para nuevas funcionalidades.
Guía Metodológica de Andamiaje Pedagógico (Scaffolded Learning)¶
Para asegurar una progresión cognitiva sólida desde los fundamentos sintácticos hasta la creación de arquitecturas complejas de software, recomendamos abordar cada problema aplicando un proceso estructurado en cuatro etapas consecutivas:
1. Descomposición y Contratos Formales (Nivel Bloom 1-2: Recordar y Comprender)¶
Definición de Dominio: Identificá con precisión el tipo de dato y el rango de las entradas válidas.
Precondiciones y Postcondiciones: Documentá qué asume la función respecto a sus argumentos (por ejemplo, punteros no nulos, divisores distintos de cero) y qué garantías ofrece al retornar.
Firma Inmutable y Encapsulamiento: Ocultá detalles internos y utilizá cualificadores
consten punteros de solo lectura para evitar mutaciones accidentales.
2. Implementación Modular Pura (Nivel Bloom 3: Aplicar)¶
Funciones de Responsabilidad Única: Descomponé el problema en submódulos pequeños y cohesivos.
Invariantes de Bucle: Asegurá que cada iteración aproxime el estado hacia la condición de terminación, previniendo lazos infinitos y accesos fuera de rango.
Cero Efectos Secundarios: Prohibí tajantemente variables globales y mutaciones fuera del ámbito estricto de los parámetros pasados por referencia.
3. Construcción Sistemática de Vectores de Prueba (Nivel Bloom 4: Analizar)¶
Antes de dar por concluida la implementación, elaborá una tabla de pruebas exhaustiva que contemple cuatro familias críticas de vectores:
Casos Típicos / Nominales: Valores promedio representativos del dominio habitual.
Casos de Frontera (Edge Cases): Límites extremos del dominio (arreglos vacíos con tamaño 0, valores neutros
0y1, cadenas vacías"").Casos Patológicos / Error: Argumentos fuera de rango, punteros
NULL, divisores nulos o desbordamientos potenciales.Aserciones Automatizadas: Trasladá la tabla directamente a llamadas
assert(...)dentro de la funciónmain(void).
4. Auditoría y Verificación Estricta (Nivel Bloom 5-6: Evaluar y Crear)¶
Higiene de Compilación: Verificá que la compilación produzca 0 advertencias bajo las directivas institucionales más rigurosas:
-Wall -Wextra -Werror -pedantic -std=c11.Integridad Dinámica: Ejecutá las pruebas bajo AddressSanitizer y Valgrind para garantizar ausencia total de accesos inválidos, desbordamientos de pila/heap o pérdidas de memoria.
Estructura de Ejercicios por Bloques¶
Los ejercicios se organizan replicando los bloques didácticos de los apuntes para guiar tu proceso de aprendizaje de manera progresiva.
Bloque 1: Fundamentos del Control de Flujo y Modularización¶
Ejercicios iniciales para asimilar la lógica de programación, el uso de variables, condicionales, lazos iterativos, modularización mediante funciones, recursividad introductoria y compilación con Makefiles.
1. Básicos y Secuencias: Ejercicios introductorios para familiarizarse con la sintaxis de C, variables y lógica secuencial.
2. C Gradual: Ejercicios simples de traducción y asimilación gradual de sintaxis en C.
3. Algoritmos Matemáticos: Problemas centrados en teoría de números (primos, MCD, potencias y secuencias lógicas).
4. Testing y Estructura de Código: Pruebas unitarias con
assert, eliminación de variables globales, análisis de flujo de control y reglas de estilo.5. Control de Flujo y Lazos: Ejercicios de bifurcaciones condicionales y estructuras de repetición seguras.
6. Modularización y Funciones: Ejercicios para estructurar subprogramas mediante firmas, parámetros y deconstrucción funcional.
7. Librerías de Funciones: Ejercicios centrados en el diseño, encapsulamiento e implementación de módulos reutilizables
.hy.c.8. Compilación y Makefiles: Ejercicios sobre las etapas de compilación, enlazado físico y automatización de la construcción con
make.9. Refactorización de Código Ofuscado: Deconstrucción, análisis y transformación de código críptico a C limpio, idiomático y modular.
Bloque 2: Memoria¶
Ejercicios enfocados en la disposición física de datos en RAM, punteros e indirección, cadenas de caracteres, persistencia en archivos de texto, memoria dinámica en el Heap, estructuras compuestas, alias de tipos y enumeraciones.
1. Punteros e Indirección: Ejercicios para afianzar el uso de punteros, operador de dirección
&e indirección*.1b. Punteros y Ejercicios de Referencia: Ejercicios de paso por referencia simulado y manipulación de memoria.
2. Arreglos Unidimensionales: Manipulación de arreglos estáticos de tamaño fijo, búsqueda y estadísticas.
2b. Cadenas de Caracteres (Strings): Operaciones sobre strings de estilo C y su terminador nulo
\0.3. Persistencia y Archivos de Texto: Lectura y escritura persistente de archivos formateados mediante streams.
3b. Ejercicios Adicionales de Archivos: Ejercicios de manipulación de flujos de texto complejos.
4. Memoria Dinámica Básica: Asignación con
malloc,callocy liberación correcta confree.4b. Memoria Dinámica Avanzada: Detección de fugas de memoria, address sanitizers y análisis físico de fragmentación del heap.
4c. Ejercicios Auxiliares de Memoria: Ejercicios adicionales sobre alocación segura de recursos.
5. Aritmética de Punteros y Indirección: Ejercicios sobre doble indirección y bloques contiguos de memoria.
6. Estructuras Compuestas (structs): Modelado lógico y disposición en memoria física de registros y uniones.
7. Alias de Tipos y Proyectos: Uso de
typedefpara modelar y portar tipos.8. Tipos Enumerativos (enums): Ejercicios sobre enumeraciones y modelado de estados lógicos seguros.
Bloque 3: Algoritmos y Estructuras de Datos¶
Ejercicios sobre matrices multidimensionales, Tipos de Datos Abstractos (TAD), estructuras lineales (listas, pilas, colas) y análisis asintótico de complejidad.
1. Matrices Multidimensionales: Disposición Row-Major en RAM y manipulación de arreglos bidimensionales.
2. Tipos Abstractos de Datos (TAD): Encapsulamiento estricto e interfaces de TADs empleando tipos incompletos y punteros opacos.
3. Estructuras de Datos Lineales: Implementación de listas enlazadas, pilas y colas dinámicas.
4. Análisis de Complejidad: Ejercicios teóricos y empíricos sobre notación asintótica Big-O, límites de hardware y Teorema Maestro.
5. Recursividad: Diseño de casos base explícitos, árboles de llamadas recursivas y algoritmos sobre secuencias.
Bloque 4: Temas Avanzados¶
Ejercicios de nivel avanzado sobre callbacks, operaciones bitwise, archivos binarios, recursividad avanzada, búsqueda/ordenamiento, análisis de código y diseño de APIs.
1. Punteros Avanzados y Callbacks: Punteros a funciones y diseño genérico parametrizado.
2. Operaciones con Bits (Bitwise): Manipulación de banderas a bajo nivel y operadores a nivel de bits.
3. Archivos Binarios: Lectura, escritura y procesamiento físico de archivos estructurados en formato binario.
4. Recursividad Avanzada: Algoritmos de backtracking, divide y conquista y memoización dinámica.
5. Búsqueda y Ordenamiento Avanzado: Algoritmos eficientes de ordenamiento por comparación y búsqueda no lineal.
6. Análisis y Debugging de Código: Lectura, comprensión formal y depuración de bases de código heredadas.
7. Diseño Profesional de APIs: Principios arquitectónicos de claridad, minimalismo, ocultamiento, versionado e ingeniería de APIs en C.
Matriz Pedagógica y Resultados de Aprendizaje¶
El plan formativo de la cátedra articula las competencias según la Taxonomía de Bloom Revisada:
| Bloque Temático | Nivel Cognitivo Principal | Competencia Adquirida | Evidencia Evaluativa |
|---|---|---|---|
| Bloque 1: Fundamentos | Nivel 1 (Recordar) a Nivel 3 (Aplicar) | Control de flujo, descomposición algorítmica modular y compilación limpia | Programas compilables con 0 warnings bajo C11 |
| Bloque 2: Memoria | Nivel 3 (Aplicar) a Nivel 4 (Analizar) | Gestión del direccionamiento físico, aritmética de punteros y Heap seguro | Cero fugas de memoria con ASan y Valgrind |
| Bloque 3: Algoritmos | Nivel 4 (Analizar) a Nivel 5 (Evaluar) | Abstracción con Tipos Opacos (TADs) y medición de complejidad temporal/espacial | Instrumentación empírica y contrastación Big-O |
| Bloque 4: Avanzados | Nivel 5 (Evaluar) a Nivel 6 (Crear) | Diseño de APIs seguras, callbacks de orden superior y persistencia binaria | Arquitecturas basadas en handles y FSM |
Verificación Automatizada y Entorno de Pruebas¶
Toda solución debe validarse localmente antes de integrarse al repositorio mediante el arnés de verificación institucional:
1. Verificación Estructural y de Reglas de Calidad¶
Comprueba que los bloques {exercise}, tablas de prueba obligatorias y soluciones {solution} cumplan con el estándar de documentación:
node ejercicios/verificar_calidad.mjs2. Extracción, Compilación C11 y Ejecución de Aserciones¶
Extrae automáticamente los bloques de código C, invoca a gcc bajo directivas estrictas y ejecuta las aserciones de prueba en un entorno seguro:
node ejercicios/verificar_ejercicios.mjsBanderas de Compilación Requeridas:
gcc -Wall -Wextra -Werror -pedantic -std=c11 solucion.c -o solucion3. Criterio de Aceptación Institucional¶
Una entrega o solución se considera aprobada únicamente cuando:
Compila con cero advertencias (0 warnings) y cero errores.
Todas las aserciones
assert(...)delmain(void)retornan con código de salida0.No existen accesos fuera de límites (out-of-bounds) ni dobles liberaciones (double-free).
El mensaje de commit respeta la convención de commits semánticos (Conventional Commits).