💩

programierds

PROGRAMIERDS_OS v1.0.4 // TOPIC: MODULARIDAD_C

Modularization

in C

Subprograms, Functions, Procedures and the art of dividing to conquer.

↓ scroll to continue


What is Modularization?

Breaking a large problem into small, manageable parts

✗ The Monolith

// main.c — 500 lines of terror int main() { // read data... // validate input... // calculate result... // format output... // save to file... // print to screen... // ... 490 more lines }
One giant block. If something fails, everything explodes.

✓ Modularized

leerDatos()
validarEntrada()
calcularResultado()
formatearSalida()
guardarArchivo()
Small, independent, reusable pieces. Like LEGO.

ANALOGY

You don't sculpt from a whole rock — you build with LEGO. Each piece has a defined shape, fits with others, and can be reused in any construction.


Subprograms

In C, every subprogram is a function. There is nothing else.

Anatomy of a Function

RETURN_TYPE — what it returns
NAME — function identifier
PARAMETERS — input data
BODY — logic and instructions
int sumar(int a, int b) {
int resultado = a + b;
return resultado;
}

REUSABILITY

Once defined, the function can be called infinitely many times from any part of the program.

ABSTRACTION

You don't need to know how it works to use it. Only what it receives and what it returns.

int x = sumar(3, 7); // x = 10
int y = sumar(100, 200); // y = 300
int z = sumar(x, y); // z = 310

Functions vs Procedures

The difference is whether they return something or not

PROCEDURE

void — executes an action, returns nothing

data IN
imprimirMenu()
✗ no return

Like a worker who does the task and thats it

void imprimirMenu() {
printf("1. Ingresar\n");
printf("2. Salir\n");
// no hay return
}

FUNCTION

with return type — calculates and returns a value

a, b IN
sumar(a, b)
result OUT

Like a worker who brings back the result

int sumar(int a, int b) {
return a + b;
}
int r = sumar(3, 4); // r = 7

Local Variables

They live inside the function. When it ends, they disappear.

EXECUTION STACK

▼ main()
argc = 1
▼ calcular()
base = 10 altura = 5 area = 50
↑ only exist here inside
STACK

Each call stacks a new "drawer" with its local vars

int calcular(int base, int altura) {
int area = base * altura;
return area;
}

int main() {
int r = calcular(10, 5);
// 'area' DOES NOT exist here
// printf("%d", area); → ERROR
}

⚠ Compilation Error

Trying to use area outside of calcular() fails. The local variable does not exist outside its scope. The compiler tells you right to your face.


Global Variables

Declared outside any function. Everyone can see them... and modify them.

GLOBAL VARIABLE

int contador = 0;
funcionA() can read and write contador
funcionB() can read and write contador
main() can read and write contador
int contador = 0; // GLOBAL

void incrementar() {
contador++;
}

void resetear() {
contador = 0;
}

int main() {
incrementar();
incrementar();
resetear(); // surprise!
}

⚠ DANGER: Ghost Effect

resetear() modifies contador without anyone expecting it. This kind of bug is a nightmare to debug.

Use globals only when strictly necessary.


Local vs Global

And the mystery of shadowing: when a variable hides another

int x = 100; // GLOBAL x

void miFuncion() {
int x = 5; // LOCAL x — HIDES the global
printf("%d", x); // prints 5, not 100
} // the local x disappears here

int main() {
printf("%d", x); // prints 100 (the global)
miFuncion(); // prints 5
printf("%d", x); // still 100
}

LOCAL (cyan)

Exists only inside its block. It has priority over the global of the same name within that scope. When the block ends, it disappears from the stack.

GLOBAL (amber)

Visible from any function. If a function has a local with the same name, the global becomes hidden (shadowed) inside that function.


Pass by Value

The value is copied. The original remains intact.

FRAME: main()
0xFF01
x
5
FRAME: inc()
0xFF10
n (copy)
5
1 x is 5 in the main frame
2 inc(x) is called — the value 5 is copied into n
3 Inside inc(), n becomes 6 (n++)
4 The function ends, the inc() frame is destroyed. n disappears.
5 x still equals 5. The original was not touched.
void inc(int n) {
n++; // modifies the copy, not the original
}

int main() {
int x = 5;
inc(x); // passes a COPY of x
printf("%d", x); // prints 5 — unchanged
}

Pass by Reference

The memory address is passed. The original IS modified.

FRAME: main()
0xFF01
x
5
FRAME: cambiar()
0xFF20
p (pointer)
0xFF01
1 x is 5 at address 0xFF01
2 &x (the address) is passed. The pointer p receives 0xFF01
3 *p = 10 follows the address and modifies the memory at 0xFF01
4 The function ends. p disappears, but the damage is done.
5 x now equals 10. The original was modified.
void cambiar(int *p) {
*p = 10; // dereference: modifies what it points to
}

int main() {
int x = 5;
cambiar(&x); // passes the ADDRESS of x
printf("%d", x); // prints 10 — was modified
}

Value vs Reference

Same starting point, completely different result

BY VALUE

main: 0xFF01
x
5
value is copied ↓
func: 0xFF10
n (copy)
6
x still = 5 ✔

BY REFERENCE

main: 0xFF01
x
10 ⚠
address is passed ↓
func: 0xFF20
p (ptr)
➜ 0xFF01
x now = 10 ⚠
Aspect By Value By Reference (pointer)
What is passed Copy of the value Memory address
Modifies original NO ✔ YES ⚠
Syntax at call func(x) func(&x)
Syntax at parameter int n int *p
When to use Read data, calculate Modify the original

Formal and Actual Parameters

Definition vs call. Placeholder vs real value.

FORMAL PARAMETERS

Those in the DEFINITION — are placeholders, local variables

int calcular(int base, int altura) {
return base * altura;
}
base altura

They are like normal variables inside the function. They get assigned a value at the call.

ACTUAL PARAMETERS

Those in the CALL — the real values being passed

calcular(10, 20);
10 20

These are the concrete values (literals, variables or expressions) sent in the call.

POSITIONAL CORRESPONDENCE — order matters

calcular(10, 20);
// base=10, altura=20 → result = 200

// Order DOES matter in many cases:
dividir(10, 2); // 10 / 2 = 5
dividir(2, 10); // 2 / 10 = 0 (VERY different result)

Complete Example

A program that uses EVERYTHING we saw

#include <stdio.h>

// GLOBAL: visible in all functions
int llamadas = 0;

// FUNCTION: returns the area (by value)
int areaRectangulo(int base, int altura) {
llamadas++; // modifies global
int area = base * altura; // LOCAL
return area;
}

// PROCEDURE: prints (void, no return)
void imprimirResultado(int valor) {
printf("Resultado: %d\n", valor);
}

// BY REFERENCE: duplicates the original
void duplicar(int *p) {
*p *= 2;
}

int main() {
// formals: base, altura — actuals: 5, 10
int area = areaRectangulo(5, 10);
imprimirResultado(area); // 50

duplicar(&area); // passes address — by reference
imprimirResultado(area); // 100

printf("Llamadas: %d\n", llamadas); // 1
return 0;
}

GLOBAL

llamadas — visible in all functions

LOCAL

area inside areaRectangulo — only there

POINTER

*p in duplicar — modifies the original


Golden Rules

Burn them into memory. Forever.

01

Modularize: short functions that do ONE thing

If your function needs a comment explaining what it does, its too long.

02

Prefer local variables over globals

Globals create hidden dependencies and impossible-to-track bugs.

03

Pass by value: safe, the original does not change

Use it when you only need to read or calculate something from the data.

04

Pass by reference (*pointers): when you NEED to modify the original

Be explicit. Whoever reads the code needs to know the function has side effects.

05

Formal parameters = definition, actuals = call

The order of actuals must match the order of formals. Always.

06

Each function = one responsibility

Single Responsibility Principle. It applies in C, in any language, in any paradigm.


EOF // END_OF_PRESENTATION
>_

SESSION ENDED

Now you know how to modularize in C. Now think in modules.

PROGRAMIERDS — 2026