Módulo 04: Estructuras de control
Objetivos del módulo
- Entender qué son las estructuras de control y por qué existen
- Dominar las estructuras condicionales:
if,else if,else - Usar
switchclásico y moderno (pattern matching) - Dominar los bucles:
for,while,do-while,foreach - Controlar el flujo con
break,continueyreturn - Anidar estructuras de control de forma legible
1. ¿Qué son las estructuras de control?
📘 Concepto: Las estructuras de control son instrucciones que permiten que tu programa tome decisiones (condicionales) o repita acciones (bucles). Sin ellas, el código se ejecutaría siempre de arriba a abajo, instrucción por instrucción, sin posibilidad de variar su comportamiento.
Flujo lineal (sin estructuras de control):
instrucción 1
instrucción 2
instrucción 3
instrucción 4
(siempre igual)
Flujo con decisiones:
instrucción 1
¿condición? ──→ Sí: instrucción 2a
└──→ No: instrucción 2b
instrucción 3
Flujo con bucles:
instrucción 1
┌→ instrucción 2 ←┐
│ ¿repetir? ─Sí──┘
│ └──No──→ instrucción 3
2. Condicional if
La estructura más básica de decisión: “Si se cumple esta condición, ejecuta este código”.
int edad = 20;
if (edad >= 18)
{
Console.WriteLine("Eres mayor de edad.");
Console.WriteLine("Puedes votar.");
}
Explicación línea por línea:
| Línea | Código | Explicación |
|---|---|---|
if (edad >= 18) | Evalúa si edad es mayor o igual a 18. El resultado es true o false. | |
{ | Inicio del bloque de código que se ejecutará si la condición es true. | |
Console.WriteLine(...) | Estas líneas solo se ejecutan si la condición es verdadera. | |
} | Fin del bloque. Si la condición es false, se salta todo el bloque. |
⚠️ Importante: La condición dentro del
ifsiempre debe ser una expresión que devuelvabool(trueofalse). En C#, a diferencia de otros lenguajes, no puedes usar un número como condición (por ejemplo,if (1)no es válido).
Diagrama de flujo de if
┌──────────┐
│ Inicio │
└────┬─────┘
│
┌────▼─────┐
│ ¿edad │
│ >= 18? │
└──┬───┬───┘
Sí │ │ No
│ │
┌────▼───┐│
│ Mostrar ││
│ mensaje ││
└────┬───┘│
│ │
└──┬─┘
┌─────▼────┐
│ Fin │
└──────────┘
3. Condicional if-else
Permite ejecutar un bloque si la condición es verdadera y otro bloque diferente si es falsa.
int edad = 15;
if (edad >= 18)
{
Console.WriteLine("Eres mayor de edad.");
}
else
{
Console.WriteLine("Eres menor de edad.");
}
┌──────────────┐
│ ¿edad >= 18? │
└──┬───────┬───┘
Sí │ │ No
│ │
┌────▼───┐ ┌▼──────────┐
│ "Mayor │ │ "Menor │
│ de │ │ de │
│ edad" │ │ edad" │
└────┬───┘ └┬──────────┘
│ │
└───┬───┘
▼
4. Condicional else if
Para evaluar múltiples condiciones en cascada:
Console.Write("Introduce tu nota (0-10): ");
double nota = double.Parse(Console.ReadLine()!);
if (nota < 0 || nota > 10)
{
Console.WriteLine("Nota inválida. Debe estar entre 0 y 10.");
}
else if (nota < 5)
{
Console.WriteLine("SUSPENSO");
}
else if (nota < 6)
{
Console.WriteLine("APROBADO");
}
else if (nota < 7)
{
Console.WriteLine("BIEN");
}
else if (nota < 9)
{
Console.WriteLine("NOTABLE");
}
else
{
Console.WriteLine("SOBRESALIENTE");
}
Explicación:
| Código | Se ejecuta cuando… |
|---|---|
nota < 0 \|\| nota > 10 | La nota está fuera del rango válido |
nota < 5 | La nota es menor que 5 (y ya sabemos que está en rango porque la primera condición fue false) |
nota < 6 | La nota está entre 5 y 5.99 |
nota < 7 | La nota está entre 6 y 6.99 |
nota < 9 | La nota está entre 7 y 8.99 |
else | Cualquier otro caso: nota entre 9 y 10 |
💡 Consejo: El
!después deConsole.ReadLine()!es el operador de supresión de null. Le dice al compilador “confío en que esto no será null”. Es necesario porqueReadLine()podría devolver null.
5. Expresión switch clásica
switch es útil cuando quieres comparar una variable contra múltiples valores concretos:
Console.Write("Introduce el día de la semana (1-7): ");
int dia = int.Parse(Console.ReadLine()!);
switch (dia)
{
case 1:
Console.WriteLine("Lunes");
break;
case 2:
Console.WriteLine("Martes");
break;
case 3:
Console.WriteLine("Miércoles");
break;
case 4:
Console.WriteLine("Jueves");
break;
case 5:
Console.WriteLine("Viernes");
break;
case 6:
Console.WriteLine("Sábado (fin de semana)");
break;
case 7:
Console.WriteLine("Domingo (fin de semana)");
break;
default:
Console.WriteLine("Día inválido");
break;
}
Explicación:
| Parte | Significado |
|---|---|
switch (dia) | Evalúa la variable dia |
case 1: | Si dia vale 1, ejecuta el código de este bloque |
break; | Salir del switch. Obligatorio en C# (a diferencia de otros lenguajes) |
default: | Se ejecuta si ningún case coincide. Es como el else del switch |
Agrupar casos
Si varios valores deben ejecutar el mismo código:
switch (dia)
{
case 1:
case 2:
case 3:
case 4:
case 5:
Console.WriteLine("Día laborable");
break;
case 6:
case 7:
Console.WriteLine("Fin de semana");
break;
default:
Console.WriteLine("Día inválido");
break;
}
6. Expresión switch moderna (C# 8+)
C# moderno permite usar switch como una expresión que devuelve un valor, de forma mucho más compacta:
int dia = 3;
string nombreDia = dia switch
{
1 => "Lunes",
2 => "Martes",
3 => "Miércoles",
4 => "Jueves",
5 => "Viernes",
6 => "Sábado",
7 => "Domingo",
_ => "Día inválido" // _ es el caso por defecto (como default)
};
Console.WriteLine(nombreDia); // "Miércoles"
Pattern matching con rangos
double nota = 7.5;
string calificacion = nota switch
{
< 0 or > 10 => "Nota inválida",
< 5 => "Suspenso",
< 6 => "Aprobado",
< 7 => "Bien",
< 9 => "Notable",
<= 10 => "Sobresaliente",
_ => "Error"
};
Console.WriteLine($"Nota {nota}: {calificacion}"); // "Nota 7.5: Notable"
Pattern matching con tipos
object valor = 42;
string descripcion = valor switch
{
int n when n > 0 => $"Número positivo: {n}",
int n when n < 0 => $"Número negativo: {n}",
int => "Cero",
string s => $"Texto: {s}",
bool b => $"Booleano: {b}",
null => "Es null",
_ => $"Tipo desconocido: {valor.GetType()}"
};
Console.WriteLine(descripcion); // "Número positivo: 42"
7. Bucle while
Repite un bloque de código mientras una condición sea verdadera.
// Contar del 1 al 5
int contador = 1;
while (contador <= 5)
{
Console.WriteLine($"Contador: {contador}");
contador++;
}
Console.WriteLine("¡Fin del bucle!");
Traza de ejecución (paso a paso):
| Iteración | contador | contador <= 5 | Acción |
|---|---|---|---|
| 1 | 1 | true | Imprime “Contador: 1”, incrementa a 2 |
| 2 | 2 | true | Imprime “Contador: 2”, incrementa a 3 |
| 3 | 3 | true | Imprime “Contador: 3”, incrementa a 4 |
| 4 | 4 | true | Imprime “Contador: 4”, incrementa a 5 |
| 5 | 5 | true | Imprime “Contador: 5”, incrementa a 6 |
| 6 | 6 | false | Sale del bucle |
Diagrama:
┌──────────────────┐
│ contador = 1 │
└────────┬─────────┘
│
┌────────▼─────────┐
│ ¿contador <= 5? │◄──────┐
└──┬──────────┬────┘ │
Sí │ │ No │
│ │ │
┌────▼──────┐ │ ┌────┤
│ Mostrar │ │ │ ++ │
│ contador │───────────┘ │
└───────────┘ │ │
│
┌─────▼───┐
│ Fin │
└──────────┘
⚠️ Importante: Si la condición nunca se hace
false, el bucle será infinito y tu programa se quedará colgado. Asegúrate siempre de que algo dentro del bucle haga que la condición eventualmente seafalse.
Ejemplo práctico: Menú interactivo
string opcion = "";
while (opcion != "4")
{
Console.WriteLine("\n═══ MENÚ ═══");
Console.WriteLine("1. Saludar");
Console.WriteLine("2. Mostrar fecha");
Console.WriteLine("3. Mostrar hora");
Console.WriteLine("4. Salir");
Console.Write("Elige una opción: ");
opcion = Console.ReadLine()!;
switch (opcion)
{
case "1":
Console.WriteLine("¡Hola, bienvenido!");
break;
case "2":
Console.WriteLine($"Hoy es: {DateTime.Now:dd/MM/yyyy}");
break;
case "3":
Console.WriteLine($"Son las: {DateTime.Now:HH:mm:ss}");
break;
case "4":
Console.WriteLine("¡Hasta luego!");
break;
default:
Console.WriteLine("Opción no válida.");
break;
}
}
8. Bucle do-while
Similar al while, pero ejecuta el bloque al menos una vez antes de comprobar la condición.
int numero;
do
{
Console.Write("Introduce un número positivo: ");
numero = int.Parse(Console.ReadLine()!);
if (numero <= 0)
{
Console.WriteLine("¡Eso no es un número positivo! Inténtalo de nuevo.");
}
} while (numero <= 0);
Console.WriteLine($"Has introducido: {numero}");
Diferencia clave:
while | do-while |
|---|---|
| Comprueba la condición antes de ejecutar | Ejecuta el código primero y luego comprueba |
| Puede no ejecutarse nunca | Se ejecuta al menos una vez |
while (cond) { código } | do { código } while (cond); |
💡 Consejo: Usa
do-whilecuando necesites que el código se ejecute al menos una vez, como al pedir datos al usuario (necesitas pedirlos antes de poder comprobar si son válidos).
9. Bucle for
El bucle for es ideal cuando sabes cuántas veces quieres repetir algo.
// Sintaxis: for (inicialización; condición; actualización)
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"Iteración {i}");
}
Partes del for:
| Parte | Código | Significado |
|---|---|---|
| Inicialización | int i = 0 | Se ejecuta una sola vez al inicio. Crea la variable de control. |
| Condición | i < 5 | Se evalúa antes de cada iteración. Si es false, se sale del bucle. |
| Actualización | i++ | Se ejecuta al final de cada iteración. |
Traza:
| Paso | i | i < 5 | Acción |
|---|---|---|---|
| 1 | 0 | true | Imprime “Iteración 0” |
| 2 | 1 | true | Imprime “Iteración 1” |
| 3 | 2 | true | Imprime “Iteración 2” |
| 4 | 3 | true | Imprime “Iteración 3” |
| 5 | 4 | true | Imprime “Iteración 4” |
| 6 | 5 | false | Sale del bucle |
Variaciones del for
// Contar hacia atrás
for (int i = 10; i > 0; i--)
{
Console.Write($"{i}... ");
}
Console.WriteLine("¡DESPEGUE!");
// De 2 en 2
for (int i = 0; i <= 20; i += 2)
{
Console.Write($"{i} ");
}
// Salida: 0 2 4 6 8 10 12 14 16 18 20
// Tabla de multiplicar
int tabla = 7;
Console.WriteLine($"Tabla del {tabla}:");
for (int i = 1; i <= 10; i++)
{
Console.WriteLine($" {tabla} x {i} = {tabla * i}");
}
10. Bucle foreach
Recorre todos los elementos de una colección (array, lista, string, etc.) uno por uno, sin necesidad de usar un índice.
// foreach con un array
string[] frutas = { "Manzana", "Banana", "Cereza", "Dátil" };
foreach (string fruta in frutas)
{
Console.WriteLine($"Fruta: {fruta}");
}
// foreach con un string (recorre carácter por carácter)
string palabra = "Hola";
foreach (char letra in palabra)
{
Console.Write($"[{letra}] ");
}
// Salida: [H] [o] [l] [a]
📘 Concepto:
foreaches ideal cuando quieres recorrer todos los elementos y no necesitas saber el índice. Para acceder por índice o modificar elementos, usafor.
11. Control de flujo: break y continue
break: sale del bucle inmediatamente
// Buscar el primer número divisible por 7 entre 1 y 100
for (int i = 1; i <= 100; i++)
{
if (i % 7 == 0)
{
Console.WriteLine($"Primer múltiplo de 7: {i}");
break; // Sale del bucle
}
}
// Salida: Primer múltiplo de 7: 7
continue: salta a la siguiente iteración
// Mostrar solo los números impares del 1 al 10
for (int i = 1; i <= 10; i++)
{
if (i % 2 == 0)
{
continue; // Salta los pares
}
Console.Write($"{i} ");
}
// Salida: 1 3 5 7 9
12. Bucles anidados
Un bucle dentro de otro bucle:
// Tablas de multiplicar del 1 al 5
for (int tabla = 1; tabla <= 5; tabla++)
{
Console.WriteLine($"\n═══ Tabla del {tabla} ═══");
for (int i = 1; i <= 10; i++)
{
Console.WriteLine($" {tabla} x {i,2} = {tabla * i,3}");
}
}
Ejemplo: Dibujar un rectángulo con asteriscos
Console.Write("Ancho: ");
int ancho = int.Parse(Console.ReadLine()!);
Console.Write("Alto: ");
int alto = int.Parse(Console.ReadLine()!);
for (int fila = 0; fila < alto; fila++)
{
for (int columna = 0; columna < ancho; columna++)
{
Console.Write("* ");
}
Console.WriteLine(); // Salto de línea al final de cada fila
}
// Para ancho=5, alto=3:
// * * * * *
// * * * * *
// * * * * *
Ejemplo: Triángulo de asteriscos
int filas = 5;
for (int i = 1; i <= filas; i++)
{
for (int j = 0; j < i; j++)
{
Console.Write("* ");
}
Console.WriteLine();
}
// Salida:
// *
// * *
// * * *
// * * * *
// * * * * *
13. Ejercicios
Ejercicio 1: Número par o impar
Pide un número al usuario y muestra si es par o impar.
Ejercicio 2: Máximo de tres números
Pide tres números al usuario y muestra cuál es el mayor.
Ejercicio 3: Adivina el número
El programa “piensa” un número aleatorio entre 1 y 100. El usuario tiene que adivinarlo. El programa dice “Más alto” o “Más bajo” tras cada intento:
Random random = new Random();
int secreto = random.Next(1, 101); // Número entre 1 y 100
int intentos = 0;
int intento;
Console.WriteLine("He pensado un número entre 1 y 100. ¡Adivínalo!");
do
{
Console.Write("Tu intento: ");
intento = int.Parse(Console.ReadLine()!);
intentos++;
if (intento < secreto)
Console.WriteLine("Más alto ↑");
else if (intento > secreto)
Console.WriteLine("Más bajo ↓");
else
Console.WriteLine($"¡Correcto! Lo adivinaste en {intentos} intentos.");
} while (intento != secreto);
Ejercicio 4: Factorial
Calcula el factorial de un número usando un bucle for:
5! = 5 × 4 × 3 × 2 × 1 = 120
Ejercicio 5: Números primos
Pide un número al usuario y determina si es primo (solo divisible por 1 y por sí mismo).
Ejercicio 6: Pirámide de números
Crea esta pirámide pidiendo el número de filas:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
Ejercicio 7: FizzBuzz
Imprime los números del 1 al 100, pero:
- Si es múltiplo de 3, imprime “Fizz”
- Si es múltiplo de 5, imprime “Buzz”
- Si es múltiplo de ambos, imprime “FizzBuzz”
Solución:
for (int i = 1; i <= 100; i++)
{
string resultado = (i % 3 == 0, i % 5 == 0) switch
{
(true, true) => "FizzBuzz",
(true, false) => "Fizz",
(false, true) => "Buzz",
_ => i.ToString()
};
Console.WriteLine(resultado);
}
Resumen
| Estructura | Uso | Ejemplo |
|---|---|---|
if / else if / else | Decisiones simples o en cascada | if (x > 0) { ... } |
switch (clásico) | Comparar contra valores concretos | switch (dia) { case 1: ... } |
switch (expresión) | Devolver un valor según una condición | x switch { 1 => "uno", _ => "otro" } |
while | Repetir mientras la condición sea verdadera | while (x < 10) { ... } |
do-while | Igual que while, pero ejecuta al menos una vez | do { ... } while (x < 10); |
for | Repetir un número conocido de veces | for (int i = 0; i < 10; i++) |
foreach | Recorrer todos los elementos de una colección | foreach (var item in lista) |
break | Salir del bucle inmediatamente | if (x == 5) break; |
continue | Saltar a la siguiente iteración | if (x == 5) continue; |