Modularización
en C
Subprogramas, Funciones, Procedimientos y el arte de dividir para conquistar.
↓ scroll para continuar
¿Qué es Modularizar?
Dividir un problema grande en partes pequeñas y manejables
✘ El Monolito
✔ Modularizado
ANALOGÍA
No esculpís desde una roca entera — construyés con LEGO. Cada pieza tiene forma definida, encaja con otras, y la podés reusar en cualquier construcción.
Subprogramas
En C, todo subprograma es una función. No hay otra cosa.
Anatomía de una Función
int resultado = a + b;
return resultado;
}
REUTILIZACIÓN
Una vez definida, la función puede llamarse infinitas veces desde cualquier parte del programa.
ABSTRACCIÓN
No necesitás saber cómo funciona para usarla. Solo qué recibe y qué devuelve.
int y = sumar(100, 200); // y = 300
int z = sumar(x, y); // z = 310
Funciones vs Procedimientos
La diferencia está en si devuelven algo o no
PROCEDIMIENTO
void — ejecuta una acción, no retorna nada
Como un trabajador que hace la tarea y ya
printf("1. Ingresar\n");
printf("2. Salir\n");
// no hay return
}
FUNCIÓN
con tipo de retorno — calcula y devuelve un valor
Como un trabajador que trae de vuelta el resultado
return a + b;
}
int r = sumar(3, 4); // r = 7
Variables Locales
Viven dentro de la función. Cuando termina, desaparecen.
STACK DE EJECUCIÓN
Cada llamada apila un nuevo "cajón" con sus vars locales
int area = base * altura;
return area;
}
int main() {
int r = calcular(10, 5);
// 'area' NO existe acá
// printf("%d", area); → ERROR
}
⚠ Error de compilación
Intentar usar area fuera de calcular() falla. La variable local no existe fuera de su scope. El compilador te lo dice en la cara.
Variables Globales
Declaradas fuera de toda función. Todos pueden verlas... y modificarlas.
VARIABLE GLOBAL
void incrementar() {
contador++;
}
void resetear() {
contador = 0;
}
int main() {
incrementar();
incrementar();
resetear(); // sorpresa!
}
⚠ PELIGRO: Efecto Fantasma
resetear() modifica contador sin que nadie lo espere. Este tipo de bug es una pesadilla para debuggear.
Usá globales solo cuando sea estrictamente necesario.
Locales vs Globales
Y el misterio del shadowing: cuándo una variable oculta a otra
void miFuncion() {
int x = 5; // LOCAL x — OCULTA a la global
printf("%d", x); // imprime 5, no 100
} // la local x desaparece acá
int main() {
printf("%d", x); // imprime 100 (la global)
miFuncion(); // imprime 5
printf("%d", x); // sigue siendo 100
}
LOCAL (cyan)
Existe solo dentro de su bloque. Tiene prioridad sobre la global del mismo nombre dentro de ese scope. Cuando el bloque termina, desaparece del stack.
GLOBAL (amber)
Visible desde cualquier función. Si una función tiene una local del mismo nombre, la global queda oculta (shadowed) dentro de esa función.
Pasaje Por Valor
Se copia el valor. El original queda intacto.
x vale 5 en el frame de main inc(x) — el valor 5 se copia en n inc(), n pasa a valer 6 (n++) n desaparece. x sigue valiendo 5. El original no fue tocado. n++; // modifica la copia, no el original
}
int main() {
int x = 5;
inc(x); // pasa una COPIA de x
printf("%d", x); // imprime 5 — sin cambios
}
Pasaje Por Referencia
Se pasa la dirección de memoria. El original SÍ se modifica.
x vale 5 en dirección 0xFF01 &x (la dirección). El puntero p recibe 0xFF01 *p = 10 sigue la dirección y modifica la memoria en 0xFF01 p desaparece, pero el daño está hecho. x ahora vale 10. El original fue modificado. *p = 10; // desreferencia: modifica lo que apunta
}
int main() {
int x = 5;
cambiar(&x); // pasa la DIRECCIÓN de x
printf("%d", x); // imprime 10 — fue modificado
}
Valor vs Referencia
Mismo punto de partida, resultado completamente distinto
POR VALOR
POR REFERENCIA
| Aspecto | Por Valor | Por Referencia (puntero) |
|---|---|---|
| Qué se pasa | Copia del valor | Dirección de memoria |
| Modifica original | NO ✔ | SÍ ⚠ |
| Sintaxis en llamada | func(x) | func(&x) |
| Sintaxis en parámetro | int n | int *p |
| Cuándo usar | Leer datos, calcular | Modificar el original |
Parámetros Nominales y Efectivos
Definición vs llamada. Placeholder vs valor real.
PARÁMETROS NOMINALES
Los de la DEFINICIÓN — son placeholders, variables locales
return base * altura;
}
Son como variables normales dentro de la función. Se les asigna valor en la llamada.
PARÁMETROS EFECTIVOS
Los de la LLAMADA — los valores reales que se pasan
Son los valores concretos (literales, variables o expresiones) que se envían en la llamada.
CORRESPONDENCIA POSICIONAL — el orden importa
// base=10, altura=20 → resultado = 200
// El orden SÍ importa en muchos casos:
dividir(10, 2); // 10 / 2 = 5
dividir(2, 10); // 2 / 10 = 0 (resultado MUY diferente)
Ejemplo Completo
Un programa que usa TODO lo que vimos
// GLOBAL: visible en todas las funciones
int llamadas = 0;
// FUNCIÓN: retorna el área (por valor)
int areaRectangulo(int base, int altura) {
llamadas++; // modifica global
int area = base * altura; // LOCAL
return area;
}
// PROCEDIMIENTO: imprime (void, sin retorno)
void imprimirResultado(int valor) {
printf("Resultado: %d\n", valor);
}
// POR REFERENCIA: duplica el original
void duplicar(int *p) {
*p *= 2;
}
int main() {
// nominales: base, altura — efectivos: 5, 10
int area = areaRectangulo(5, 10);
imprimirResultado(area); // 50
duplicar(&area); // pasa dirección — por referencia
imprimirResultado(area); // 100
printf("Llamadas: %d\n", llamadas); // 1
return 0;
}
GLOBAL
llamadas — visible en todas las funciones
LOCAL
area dentro de areaRectangulo — solo ahí
PUNTERO
*p en duplicar — modifica el original
Reglas de Oro
Grabátelas. Para siempre.
Modularizá: funciones cortas que hacen UNA cosa
Si tu función necesita un comentario explicando qué hace, es demasiado larga.
Preferí variables locales sobre globales
Las globales crean dependencias ocultas y bugs imposibles de rastrear.
Paso por valor: seguro, el original no cambia
Usálo cuando solo necesitás leer o calcular algo a partir del dato.
Paso por referencia (*punteros): cuando NECESITÁS modificar el original
Sé explícito. Quien lee el código necesita saber que la función tiene efectos secundarios.
Parámetros nominales = definición, efectivos = llamada
El orden de los efectivos tiene que coincidir con el de los nominales. Siempre.
Cada función = una responsabilidad
Single Responsibility Principle. Vale en C, vale en cualquier lenguaje, vale en cualquier paradigma.
SESIÓN FINALIZADA
Ahora sabés modularizar en C. Ahora pensá en módulos.
PROGRAMIERDS — 2026