Funciones
Aprende a crear y usar funciones para organizar y reutilizar tu código
¿Qué es una función?
Imagina que tienes una receta para hacer un pastel. Cada vez que quieres un pastel, no necesitas reinventar cómo hacerlo: simplemente sigues la receta. Una función es exactamente eso: una receta de código que puedes usar una y otra vez.
Una función es un bloque de código con un nombre que realiza una tarea específica. La defines una vez y la puedes llamar (usar) las veces que quieras.
Sin funciones (código repetido):
// Calcular si 7 es primo
bool esPrimo7 = true;
for (int j = 2; j * j <= 7; j++)
if (7 % j == 0) esPrimo7 = false;
// Calcular si 13 es primo (¡el mismo código otra vez!)
bool esPrimo13 = true;
for (int j = 2; j * j <= 13; j++)
if (13 % j == 0) esPrimo13 = false;
Con funciones (código limpio):
bool esPrimo(int n) {
for (int j = 2; j * j <= n; j++)
if (n % j == 0) return false;
return n > 1;
}
// Usar la función es una sola línea
bool resultado1 = esPrimo(7); // true
bool resultado2 = esPrimo(13); // true
bool resultado3 = esPrimo(15); // false
Anatomía de una función
tipo_de_retorno nombre(tipo param1, tipo param2, ...) {
// Cuerpo de la función
return valor;
}
Veamos cada parte:
int sumar(int a, int b) {
int resultado = a + b;
return resultado;
}
int(tipo de retorno): El tipo de dato que la función devuelve. Esta función devuelve un entero.sumar(nombre): El nombre que le damos para poder llamarla.int a, int b(parámetros): Los datos que la función necesita para trabajar. Son como los "ingredientes" de la receta.return resultado: Devuelve el resultado al lugar donde se llamó la función.
Llamar una función
int main() {
int x = sumar(3, 5); // x = 8
cout << sumar(10, 20); // Imprime 30
cout << sumar(sumar(1, 2), 3); // sumar(3, 3) = 6
return 0;
}
Funciones que no devuelven nada: void
A veces una función solo hace algo (imprimir, modificar) sin devolver un valor. Para eso usamos void:
void saludar(string nombre) {
cout << "¡Hola, " << nombre << "!" << endl;
// No necesita return (o puedes poner "return;" sin valor)
}
int main() {
saludar("Carlos"); // Imprime: ¡Hola, Carlos!
saludar("María"); // Imprime: ¡Hola, María!
return 0;
}
Funciones que no reciben nada
void imprimirLinea() {
cout << "========================" << endl;
}
int main() {
imprimirLinea();
cout << "Mi Programa" << endl;
imprimirLinea();
return 0;
}
Salida:
========================
Mi Programa
========================
El orden importa
En C++, una función debe estar definida antes de ser usada. Si main llama a sumar, sumar debe estar arriba de main:
// ✅ Correcto: la función está definida ANTES de main
int sumar(int a, int b) {
return a + b;
}
int main() {
cout << sumar(3, 5) << endl;
return 0;
}
// ❌ Error: main usa sumar, pero sumar está después
int main() {
cout << sumar(3, 5) << endl; // Error: ¿qué es "sumar"?
return 0;
}
int sumar(int a, int b) {
return a + b;
}
Prototipos de función
Alternativamente, puedes declarar un prototipo (la firma de la función sin el cuerpo) al inicio:
// Prototipo (declaración)
int sumar(int a, int b);
int main() {
cout << sumar(3, 5) << endl; // Funciona porque el prototipo está arriba
return 0;
}
// Definición completa
int sumar(int a, int b) {
return a + b;
}
En competencias, normalmente ponemos todas las funciones arriba de main, así que no necesitamos prototipos.
Parámetros: paso por valor vs paso por referencia
Paso por valor (copia)
Por defecto, cuando pasas una variable a una función, se pasa una copia. La función trabaja con su propia copia y la variable original no cambia:
void duplicar(int x) {
x = x * 2;
cout << "Dentro de la función: " << x << endl; // 10
}
int main() {
int num = 5;
duplicar(num);
cout << "En main: " << num << endl; // 5 (¡no cambió!)
return 0;
}
Analogía: Le das una fotocopia de tu documento a alguien. Si escribe sobre la fotocopia, tu documento original no se afecta.
Paso por referencia (&)
Si quieres que la función modifique la variable original, usa &:
void duplicar(int &x) { // Note el & antes de x
x = x * 2;
cout << "Dentro de la función: " << x << endl; // 10
}
int main() {
int num = 5;
duplicar(num);
cout << "En main: " << num << endl; // 10 (¡SÍ cambió!)
return 0;
}
Analogía: Le das tu documento original a alguien. Si escribe sobre él, tus cambios se reflejan.
¿Cuándo usar referencia?
-
Cuando necesitas modificar la variable original:
void intercambiar(int &a, int &b) { int temp = a; a = b; b = temp; } -
Cuando pasas algo grande (como un vector) y no quieres copiarlo (es más eficiente):
// ❌ Lento: copia TODO el vector cada vez que llamas la función int sumaVector(vector<int> v) { ... } // ✅ Rápido: pasa una referencia (no copia nada) int sumaVector(vector<int> &v) { ... } // ✅ Aún mejor: const reference (rápido Y no lo modifica) int sumaVector(const vector<int> &v) { ... }
En competencias, siempre pasa vectores y strings por referencia (&). Pasarlos por valor (sin &) crea una copia cada vez, lo cual puede hacer tu programa mucho más lento.
Variables locales y globales
Variables locales
Una variable declarada dentro de una función solo existe dentro de esa función:
void miFuncion() {
int x = 10; // x solo existe aquí
cout << x << endl;
}
int main() {
miFuncion();
// cout << x; // ❌ Error: x no existe aquí
return 0;
}
Variables globales
Una variable declarada fuera de todas las funciones es global y accesible desde cualquier función:
int contador = 0; // Variable global
void incrementar() {
contador++; // Puede acceder a la variable global
}
int main() {
incrementar();
incrementar();
incrementar();
cout << contador << endl; // 3
return 0;
}
En competencias, es común usar variables globales para arreglos grandes (como int arr[100001]), porque las variables globales se inicializan a cero automáticamente y no tienen el límite de tamaño de las variables locales (el stack tiene límite, el segmento de datos estáticos no).
return termina la función
return no solo devuelve un valor; también termina la ejecución de la función inmediatamente:
int buscar(int arr[], int n, int objetivo) {
for (int i = 0; i < n; i++) {
if (arr[i] == objetivo) {
return i; // Encontrado: retorna la posición y TERMINA
}
}
return -1; // No encontrado
}
En funciones void, puedes usar return; (sin valor) para salir temprano:
void procesar(int x) {
if (x < 0) {
cout << "Número negativo, no procesar" << endl;
return; // Sale de la función
}
cout << "Procesando: " << x << endl;
}
Funciones útiles en competencias
Verificar si es primo
bool esPrimo(int n) {
if (n < 2) return false;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) return false;
}
return true;
}
Potencia modular
long long potMod(long long base, long long exp, long long mod) {
long long result = 1;
base %= mod;
while (exp > 0) {
if (exp % 2 == 1) {
result = result * base % mod;
}
exp /= 2;
base = base * base % mod;
}
return result;
}
Máximo Común Divisor (GCD)
int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
// O simplemente usa __gcd(a, b) que ya viene en C++
Mínimo Común Múltiplo (LCM)
int lcm(int a, int b) {
return a / gcd(a, b) * b; // Dividimos primero para evitar overflow
}
El template de competencia usa funciones
¿Recuerdas el template?
#include <bits/stdc++.h>
using namespace std;
void solve() {
// Tu solución va aquí
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 1;
// cin >> t;
while (t--) {
solve();
}
return 0;
}
La función solve() contiene tu solución. Esto es útil porque:
- Si hay múltiples casos, solo descomentas
cin >> t. - Puedes usar
returndentro desolve()para terminar un caso temprano sin terminar todo el programa. - Las variables locales de
solve()se reinician automáticamente en cada caso.
Ejercicio de práctica
Escribe una función int factorial(int n) que calcule el factorial de n. Luego lee un número y muestra su factorial.
Entrada: 5
Salida: 120 (porque 5! = 5×4×3×2×1 = 120)
Ver solución
#include <iostream>
using namespace std;
long long factorial(int n) {
long long resultado = 1;
for (int i = 2; i <= n; i++) {
resultado *= i;
}
return resultado;
}
int main() {
int n;
cin >> n;
cout << factorial(n) << endl;
return 0;
}
Nota: Usamos long long porque los factoriales crecen muy rápido. 20! ya es más de , que apenas cabe en un long long. ¡21! ya no cabe!
Siguiente paso
Con funciones dominadas, estás listo para aprender las Estructuras de Datos fundamentales: arreglos, vectores, strings y más.
