Estructuras de Control y Modularidad

2.09 · Funciones: Definición, Parámetros y Retorno

PF-209 ⏱ 90 min ⭐ 120 XP intermedio

🎯 Objetivo de aprendizaje

Al terminar este tema vas a poder:

  1. Definir funciones en C++ con tipo de retorno, nombre, parámetros y cuerpo.
  2. Llamar funciones desde main y desde otras funciones.
  3. Pasar argumentos por valor a las funciones.
  4. Devolver valores con return desde una función.
  5. Aplicar el principio "una función, una responsabilidad".
  6. Escribir prototipos (declaraciones anticipadas) de funciones.
  7. Usar parámetros por defecto para hacer funciones más flexibles.

Las funciones son los "ladrillos" de un programa. Con ellas, divides un problema grande en problemas pequeños, cada uno resuelto por una función. Esto hace tu código legible, testeable y reutilizable.

🧠 Teoría y conceptos — 2.9.1 — El problema: programas monolíticos

El problema: programas monolíticos
El problema: programas monolíticos

Qué es un programa monolítico

Un programa monolítico es aquel que tiene toda la lógica en main (o en un solo bloque). Ya escribiste varios. Funcionan, pero son difíciles de:

  • Leer: un main de 200 líneas abruma.
  • Testear: no puedes probar pedazos por separado.
  • Reutilizar: la lógica está atada al programa específico.
  • Mantener: un cambio en una parte puede romper otras.

La solución: funciones

Una función es un bloque de código con nombre que:

  • Hace una sola cosa bien hecha.
  • Puede recibir datos de entrada (parámetros).
  • Puede devolver un resultado (valor de retorno).
  • Se puede llamar desde cualquier parte del programa.
Cuaderno físico (obligatorio)

toma un programa tuyo del LAB anterior que tenga más de 50 líneas en `main`. Identifica 3 bloques de lógica que podrían ser funciones separadas.

2.9.2 — Anatomía de una función

Anatomía de una función
Anatomía de una función

Sintaxis en C++

tipoRetorno nombreFuncion(tipo1 param1, tipo2 param2, ...) {

// cuerpo de la función

// ...

return valor;  // Si la función no es void

}

Las 4 partes

Ejemplo: función que suma dos números

int sumar(int a, int b) { // tipo=int, nombre=sumar, params=(a, b)

int resultado = a + b; // cuerpo

return resultado;        // retorno

}

Funciones void: no devuelven nada

Si una función solo hace algo pero no devuelve un valor, usa void como tipo de retorno y omite el return (o usa return; sin valor).

void saludar(string nombre) {

cout << "¡Hola, " << nombre << "!" << endl;
// No hay return (void)

}

Cuaderno físico (obligatorio)

la sintaxis de función. Memorízala: `tipo nombre(parámetros) { cuerpo }`.

2.9.3 — Definir y llamar funciones

Definir y llamar funciones
Definir y llamar funciones

El flujo

  1. Definir la función (escribirla).
  2. Llamar la función desde main u otra función.
  3. La función ejecuta su cuerpo y (si aplica) devuelve un valor.

Ejemplo completo

#include <iostream>
#include <string>
using namespace std;

// Definición de la función

int sumar(int a, int b) {

return a + b;

}

int main() {

int x = 5, y = 3;

int resultado = sumar(x, y); // Llamada a la función

cout << "Suma: " << resultado << endl;  // 8
return 0;

}

Diagrama de flujo de la llamada a función

┌─────────────┐

│ INICIO │ ⬭

└──────┬──────┘

│

▼

╱─────────────╲

║ x = 5, y = 3 ║ ▭

╚════════╤══════╝

│

▼

┌──────────────────┐

│ LLAMAR sumar(x,y)│ ─────┐

└─────────┬────────┘ │

│ │

▼ │

┌─────────────┐ │

│ INICIO │ ⬭ │

└──────┬──────┘ │

│ │

▼ │

╔═════════════╗ │

║ a = 5, b = 3 ║ ▭ │

║ return a + b ║         │

╚══════╤══════╝ │

│ │

▼ │

┌─────────────┐ │

│ FIN │ ⬭ │

└──────┬──────┘ │

│ │

└───► 8 ────────►│

│

▼

╔══════════════╗

║ resultado = 8 ║ ▭

╚══════╤═══════╝

│

▼

┌─────────────┐

│ FIN │ ⬭

└─────────────┘

Lo que muestra el diagrama: la llamada a función es una "subrutina" en el flujo. El control pasa a la función, ejecuta su cuerpo, y devuelve un valor al punto de llamada.

Llamadas anidadas

Una función puede llamar a otra función:

int duplicar(int x) { return x * 2; }
int sumar(int a, int b) { return a + b; }
int main() {

int resultado = sumar(duplicar(3), duplicar(5)); // sumar(6, 10) = 16

cout << resultado << endl;
return 0;

}

Traza: duplicar(3) = 6, duplicar(5) = 10, sumar(6, 10) = 16.

Una función, una responsabilidad

// ❌ MAL: la función hace 3 cosas

void procesarEstudiante(string nombre, double calificaciones[], int n) {

// 1. Validar

if (nombre == "") { cout << "Inválido"; return; }

// 2. Calcular promedio

double suma = 0;

for (int i = 0; i < n; i++) suma += calificaciones[i];

double promedio = suma / n;

// 3. Imprimir

cout << nombre << ": " << promedio << endl;

}

// ✅ BIEN: 3 funciones, cada una hace 1 cosa

bool esNombreValido(string nombre) { return !nombre.empty(); }

double calcularPromedio(double calificaciones[], int n) {

double suma = 0;

for (int i = 0; i < n; i++) suma += calificaciones[i];
return suma / n;

}

void imprimirReporte(string nombre, double promedio) {

cout << nombre << ": " << promedio << endl;

}

Cuaderno físico (obligatorio)

la regla de "una función, una responsabilidad". Memorízala.

2.9.4 — Parámetros: cómo recibir datos

Parámetros: cómo recibir datos
Parámetros: cómo recibir datos

Paso por valor (por copia)

En C++ por defecto, los argumentos se pasan por valor: la función recibe una COPIA del valor original. Modificar el parámetro NO afecta a la variable original.

void incrementar(int x) {

x++; // Solo modifica la copia local

}

int main() {

int n = 5;

incrementar(n);

cout << n;  // 5, NO 6

}

Múltiples parámetros

double calcularIMC(double peso, double estatura) {

assert(estatura > 0);

return peso / (estatura * estatura);

}

0 parámetros

int obtenerNumeroAleatorio() {

return rand() % 100;  // número entre 0 y 99

}

Parámetros con valores por defecto

void saludar(string nombre, string saludo = "Hola") {

cout << saludo << ", " << nombre << endl;

}

int main() {

saludar("Ana"); // "Hola, Ana"

saludar("Ana", "Buenos días"); // "Buenos días, Ana"

}

Cuaderno físico (obligatorio)

los 4 tipos de funciones según parámetros (sin parámetros, 1, varios, con defaults). Da un ejemplo de cada uno.

2.9.5 — Valor de retorno: cómo devolver datos

Valor de retorno: cómo devolver datos
Valor de retorno: cómo devolver datos

return termina la función

int dividir(int a, int b) {

if (b == 0) {
return -1;  // Termina inmediatamente con -1

}

return a / b;

}

Múltiples return (en diferentes caminos)

string clasificarEdad(int edad) {

if (edad < 0) return "Inválida";
if (edad < 12) return "Niño";
if (edad < 18) return "Adolescente";
if (edad < 65) return "Adulto";
return "Adulto mayor";  // Si ninguna anterior se cumplió

}

Función void: sin retorno

void saludar() {

cout << "¡Hola!" << endl;

// No hay return

}

void despedirse() {

cout << "¡Adiós!" << endl;

return; // Opcional en void

}

Función que retorna un booleano

Patrón muy común para validaciones:

bool esValido(int edad) {

return edad >= 0 && edad <= 150;

}

// Uso:

if (esValido(edad)) {
cout << "Edad válida" << endl;
} else {
cout << "Edad inválida" << endl;

}

2.9.6 — Prototipos: declarar antes de usar

Prototipos: declarar antes de usar
Prototipos: declarar antes de usar

El problema

En C++, si llamas a una función antes de definirla, el compilador no sabe qué hace y da error.

// ❌ ERROR: el compilador no conoce "saludar" en main

int main() {

saludar("Ana");

}

void saludar(string nombre) { // Definición después de la llamada

cout << "Hola " << nombre << endl;

}

La solución: prototipos

Un prototipo (o declaración) le dice al compilador "esta función existe, sus parámetros son estos, y devuelve este tipo". Puede ir ANTES de la definición.

// Prototipo

int sumar(int a, int b);

int main() {
cout << sumar(3, 5);  // ✅ Ahora el compilador sabe qué es
return 0;

}

// Definición

int sumar(int a, int b) {

return a + b;

}

Archivos de cabecera (avanzado)

En proyectos grandes, los prototipos van en archivos .h (header) y las definiciones en archivos .cpp. Veremos esto en detalle en el Tema 2.10.

Cuaderno físico (obligatorio)

cuándo y cómo usar prototipos. Memorízalo: en programas con varias funciones, los prototipos van al inicio.

2.9.7 — Parámetros por defecto

Declaración

double calcularPrecio(double precioBase, double iva = 0.16, double descuento = 0) {

return precioBase * (1 + iva) * (1 - descuento);

}

int main() {
cout << calcularPrecio(1000);              // 1000 * 1.16 = 1160
cout << calcularPrecio(1000, 0.10);       // 1000 * 1.10 = 1100
cout << calcularPrecio(1000, 0.16, 0.20);  // 1000 * 1.16 * 0.80 = 928

}

Reglas

  • Los parámetros con default van al final de la lista.
  • Si un parámetro tiene default, todos los siguientes también deben tener default.
Cuaderno físico (obligatorio)

las reglas de los parámetros por defecto. Da un ejemplo propio.

2.9.8 — Alcance de variables (introducción)

Variables locales

Las variables declaradas dentro de una función existen solo dentro de esa función.

void miFuncion() {

int x = 5; // x existe solo aquí

cout << x;  // OK

}

int main() {

miFuncion();

cout << x;  // ❌ ERROR: x no existe aquí

}

Variables globales

Las variables declaradas fuera de cualquier función existen en todo el programa.

int contadorGlobal = 0; // Variable global

void incrementar() {

contadorGlobal++;

}

int main() {

incrementar();

cout << contadorGlobal;  // 1
return 0;

}

Variables locales con el mismo nombre

int x = 10; // Global

void miFuncion() {

int x = 5; // Local, OCULTA a la global

cout << x;  // 5 (la local)

}

int main() {
cout << x;  // 10 (la global)

miFuncion();

return 0;

}

Regla: usa variables locales siempre que puedas. Las globales son propensas a errores porque cualquier función puede modificarlas.

Cuaderno físico (obligatorio)

la diferencia entre local y global. Da un ejemplo de cuándo usar cada una.

🤖 IA como copiloto — 🤖 AI Mission 2.9

Prompt 1: "Te voy a pegar un main largo. NO me lo corrijas. Solo dime: (1) qué bloques de código podrían ser funciones separadas, (2) qué nombres descriptivos les pondrías. Máximo 150 palabras."

Prompt 2: "Necesito una función en C++ que calcule el área de un círculo. Usa el patrón: nombre descriptivo, parámetro por valor, tipo de retorno double, assert en el cuerpo. Dame el código y explícame cada parte. No me corrijas nada. Máximo 200 palabras."

🧪 Laboratorio — 🧪 LAB 2.9 — 8 ejercicios de funciones

🛠️ Herramienta recomendada para los diagramas de flujo de este LAB: Para los ejercicios que pidan un diagrama de flujo, usa [draw.io (diagrams.net)](https://app.diagrams.net/) — herramienta gratis, sin registro, que funciona en el navegador. Tiene plantillas con la simbología ANSI/ISO lista (en `General → Flowchart`). Exporta tus diagramas como PNG e insértalos en tu cuaderno digital o entrégalos junto con el código.

Ejercicio 1 — Función "saludar" (básico, 10 min)

Enunciado. Crea una función void saludar(string nombre) que imprima "¡Hola, [nombre]!". Llámala desde main con 3 nombres diferentes.

Rúbrica (10 pts): función (4 pts) + 3 llamadas (3 pts) + compilación (3 pts).

Ejercicio 2 — Función "esPar" (básico, 15 min)

Enunciado. Crea una función bool esPar(int n) que devuelva true si n es par. Escribe 5 tests con assert (cubre normal, borde, negativo).

Rúbrica (10 pts): función (4 pts) + 5 tests (4 pts) + compilación (2 pts).

Ejercicio 3 — Función "mayor de 3" (básico, 20 min)

Enunciado. Crea una función int mayorDeTres(int a, int b, int c) que devuelva el mayor de 3 números. Sin usar arreglos ni funciones auxiliares (hazlo con if-else anidados o encadenados).

Rúbrica (10 pts): función (5 pts) + 5 tests (5 pts).

Ejercicio 4 — Función "factorial" (intermedio, 25 min)

Enunciado. Crea una función recursiva o iterativa int factorial(int n) que calcule n!. Maneja n=0 (devuelve 1) y n<0 (assert falla o mensaje de error).

Rúbrica (10 pts): función (5 pts) + casos borde (3 pts) + tests (2 pts).

Ejercicio 5 — Función "esPrimo" (intermedio, 25 min)

Enunciado. Crea bool esPrimo(int n). Un primo solo es divisible entre 1 y sí mismo. Escribe 5 tests.

Rúbrica (10 pts): algoritmo (5 pts) + 5 tests (5 pts).

Ejercicio 6 — Función con menú (avanzado, 30 min)

Enunciado. Construye un menú con 3 opciones (calcular área, perímetro, salir) usando do-while + switch + funciones. Cada opción llama a una función diferente.

Rúbrica (10 pts): 3 funciones (5 pts) + menú (3 pts) + repetición (2 pts).

Ejercicio 7 — Refactor de programa monolítico (avanzado, 30 min)

Enunciado. Toma el programa de "Calculadora de Calificaciones" del Boss 1. Refactorízalo para que main solo llame a funciones (no tenga lógica). Cada función hace una sola cosa.

Rúbrica (10 pts): 5+ funciones (5 pts) + main limpio (3 pts) + comportamiento idéntico (2 pts).

Ejercicio bonus — Calculadora científica (opcional, 30 min)

Enunciado. Crea una calculadora científica con funciones para: sumar, restar, multiplicar, dividir, potencia, raíz cuadrada, seno, coseno, logaritmo. Usa <cmath>.

Rúbrica bonus (5 pts): 6+ funciones matemáticas (3 pts) + menú (1 pt) + tests (1 pt).

🎯 Cierre del tema

Lo que aprendiste hoy:

  • La anatomía completa de una función: tipo, nombre, parámetros, cuerpo.
  • Cómo definir y llamar funciones.
  • Paso por valor (por copia) y cómo afecta a las variables originales.
  • Tipos de retorno (int, double, string, bool, void).
  • Prototipos para llamar funciones antes de definirlas.
  • Parámetros por defecto.
  • Variables locales vs globales.
  • La regla "una función, una responsabilidad".

Lo que sigue: en el Tema 2.10 — Modularidad: Scope, Paso por Valor/Referencia, Multi-archivo (8h), vas a profundizar en cómo las funciones interactúan entre sí: cómo se comunican con valores, cómo se comparten datos, y cómo organizar un programa en múltiples archivos .cpp y .h. Es la base de los proyectos profesionales.

XP obtenida al completar este tema: 100 base + 30 por LAB (8 ejercicios) + 20 por Quest = 150 XP.

*"Un programa sin funciones es un muro de ladrillos pegados con la lengua. Un programa con funciones es un edificio con columnas."* — De la introducción de este manual.

Fin del Tema 2.9

📝 Quest · Cuestionario — 📝 Quest — Reactivos para autoevaluación

Las siguientes preguntas te sirven para autoevaluarte después de leer el tema. Responde en tu cuaderno o mentalmente, y luego revisa las Respuestas modelo (disponibles en libre acceso, sin iniciar sesión).

Sección A · Opción múltiple

Elige la opción correcta (A, B, C o D). Las respuestas están en la sección Respuestas modelo.

  1. ¿Qué es una función en C++?
    • Un tipo de variable
    • Un bloque de código reutilizable con nombre
    • Un bucle
    • Un comentario
  2. Sintaxis de declaración de función:
    • function nombre()
    • tipo_retorno nombre(params) { cuerpo }
    • def nombre():
    • func nombre() {}
  3. ¿Qué significa void en una función?
    • Variable vacía
    • La función no retorna valor
    • Función sin parámetros
    • Función privada
  4. return en una función void:
    • Obligatorio
    • Opcional, pero sale de la función
    • Prohibido
    • Hace nada
  5. ¿Cómo se llama una función en C++?
    • call nombre()
    • nombre();
    • invoke nombre
    • do nombre()
  6. Parámetros por valor:
    • Modifican el original
    • Reciben una copia, no afectan al original
    • Comparten memoria
    • Son referencias
  7. Parámetros por referencia (&):
    • Copia
    • Operan sobre la variable original
    • Son constantes
    • No existen
  8. Sobrecarga de funciones:
    • Funciones con el mismo nombre y misma firma
    • Funciones con el mismo nombre pero diferentes parámetros
    • Funciones sin nombre
    • Funciones globales
  9. Recursividad:
    • Bucle
    • Función que se llama a sí misma
    • Variable estática
    • Compilador
  10. ¿Por qué las funciones deben ser pequeñas?
    • Compilan más rápido
    • Más fáciles de leer, testear y mantener
    • Caben en pantalla
    • No es importante

Sección B · Preguntas abiertas

Desarrolla tu respuesta en al menos 3 líneas. Compara con la respuesta modelo después de escribir.

  1. ¿Por qué es importante que las funciones tengan una sola responsabilidad?
    → Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
  2. Diseña una función "calcularPromedio(vector<int> notas)" en C++ pseudocódigo.
    → Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…
  3. Explica la diferencia entre parámetro por valor, por referencia y por puntero. ¿Cuándo usar cada uno?
    → Escribe tu respuesta aquí (en tu cuaderno o mentalmente)…

🟢 Cuando termines, revisa las Respuestas modelo y compáralas con las tuyas. La mejor forma de aprender es discutir cada respuesta contigo mismo o con un compañero.

← Volver a temas del capítulo 📚 Ver todos los temas 🔑 Inicia sesión para hacer el Test