Estructuras de Control. Arrancamos este capítulo donde vamos a abordar uno de los elementos clave en cualquier lenguaje de programación. Las estructuras de control nos permiten dirigir el flujo de ejecución de un programa en C, tomando decisiones y repitiendo bloques de código según condiciones específicas. Aprenderemos a utilizar instrucciones condicionales como if
, else
y switch
para ejecutar distintas acciones dependiendo del valor de ciertas variables, así como bucles como while
, for
y do...while
para repetir instrucciones de forma controlada. También veremos sentencias especiales como break
y continue
que alteran el flujo dentro de los bucles. Empezamos!!!
3.1 Sentencias condicionales (if
, else
, switch
)
En programación, los condicionales son estructuras que permiten tomar decisiones durante la ejecución de un programa. En el lenguaje C, las decisiones se toman evaluando expresiones booleanas (que resultan en verdadero o falso) y ejecutando distintos bloques de código según el resultado.
Sintaxis básica del if
if (condición) {
// Código que se ejecuta si la condición es verdadera
}
La condición se evalúa como verdadera si su resultado es distinto de cero (en C, 0 es falso, y cualquier otro valor es verdadero). Si la condición se cumple, el bloque de código dentro del if
se ejecuta.
Ejemplo:
#include <stdio.h>
int main() {
int edad = 20;
if (edad >= 18) {
printf("Eres mayor de edad.\n");
}
return 0;
}
Explicación: El programa declara una variable edad
con valor 20. Como 20 >= 18
es verdadero, se imprime «Eres mayor de edad».
if
+ else
Cuando queremos ejecutar un bloque de código en caso contrario, usamos else
.
if (condición) {
// Se ejecuta si la condición es verdadera
} else {
// Se ejecuta si la condición es falsa
}
Ejemplo:
#include <stdio.h>
int main() {
int numero = -5;
if (numero > 0) {
printf("El número es positivo.\n");
} else {
printf("El número es negativo o cero.\n");
}
return 0;
}
Explicación: En este caso, como numero
es -5, la condición numero > 0
es falsa, por lo tanto se ejecuta el bloque del else
.
if
, else if
, else
Cuando hay múltiples condiciones que queremos evaluar en orden, usamos else if
.
if (condición1) {
// Se ejecuta si condición1 es verdadera
} else if (condición2) {
// Se ejecuta si condición2 es verdadera
} else {
// Se ejecuta si ninguna de las anteriores es verdadera
}
Ejemplo completo:
#include <stdio.h>
int main() {
int nota = 85;
if (nota >= 90) {
printf("Sobresaliente\n");
} else if (nota >= 70) {
printf("Aprobado\n");
} else {
printf("Reprobado\n");
}
return 0;
}
Explicación:
- Si la
nota
es mayor o igual a 90, se imprime «Sobresaliente». - Si no, pero es mayor o igual a 70, se imprime «Aprobado».
- En cualquier otro caso (nota < 70), se imprime «Reprobado».
Consideraciones a tener en cuenta:
- Paréntesis obligatorios: Siempre debes poner la condición entre paréntesis
()
. - Bloques opcionales: Si el cuerpo del
if
oelse
es de una sola línea, las llaves{}
son opcionales, pero es buena práctica usarlas siempre para evitar errores. - Encadenamiento de
if...else
: Puedes usar tantoselse if
como necesites.
Ejemplo práctico adicional
#include <stdio.h>
int main() {
int temperatura;
printf("Introduce la temperatura: ");
scanf("%d", &temperatura);
if (temperatura > 30) {
printf("Hace calor.\n");
} else if (temperatura >= 15) {
printf("Clima templado.\n");
} else if (temperatura >= 0) {
printf("Hace frío.\n");
} else {
printf("¡Temperatura bajo cero!\n");
}
return 0;
}
Explicación: El programa pide al usuario que introduzca una temperatura y luego clasifica el clima dependiendo del valor ingresado, usando múltiples else if
3.2 Bucles en C: for
y while
Los bucles permiten repetir un bloque de instrucciones mientras se cumpla una condición. C cuenta con varios tipos de bucles, siendo los más usados:
for
: Se usa cuando conocemos de antemano cuántas veces queremos repetir algo.while
: Se usa cuando no se sabe con certeza cuántas iteraciones serán necesarias, y depende de una condición que puede cambiar en el tiempo.
Bucle for
Sintaxis:
for (inicialización; condición; incremento/decremento) {
// Código que se ejecuta mientras la condición sea verdadera
}
- Inicialización: se ejecuta una vez al comienzo del bucle.
- Condición: se evalúa en cada iteración; si es falsa, el bucle termina.
- Incremento/Decremento: se ejecuta al final de cada iteración.
Veamoslos con un Ejemplo, vamos aimprimir los números del 1 al 5
#include <stdio.h>
int main() {
for (int i = 1; i <= 5; i++) {
printf("Número: %d\n", i);
}
return 0;
}
Explicación:
int i = 1
: inicializa la variable de control.i <= 5
: mientras la condición sea verdadera, el bucle continúa.i++
: incrementai
en cada ciclo.
Veamos og
Veamos otro ejemplo: Vamos a hacer un programa pra sumar los primeros 100 números naturales
#include <stdio.h>
int main() {
int suma = 0;
for (int i = 1; i <= 100; i++) {
suma += i;
}
printf("La suma de los primeros 100 números naturales es: %d\n", suma);
return 0;
}
Explicación: Se recorre del 1 al 100 y en cada paso se suma i
a la variable suma
.
Bucle while
El bucle while
evalúa la condición antes de cada iteración. Si la condición es falsa desde el principio, el bloque no se ejecuta ni una sola vez.
Sintaxis:
while (condición) {
// Código que se ejecuta mientras la condición sea verdadera
}
Veamos como contar hasta 5 utilizando un bucle while.
#include <stdio.h>
int main() {
int contador = 1;
while (contador <= 5) {
printf("Contador: %d\n", contador);
contador++;
}
return 0;
}
Explicación:
- El bucle se ejecuta mientras
contador
sea menor o igual a 5. contador++
incrementa el valor para evitar un bucle infinito.
Hagamos otro ejemplo para leer números hasta que el usuario introduzca 0
#include <stdio.h>
int main() {
int numero;
printf("Introduce números (0 para salir): ");
scanf("%d", &numero);
while (numero != 0) {
printf("Ingresaste: %d\n", numero);
printf("Introduce otro número (0 para salir): ");
scanf("%d", &numero);
}
printf("Programa terminado.\n");
return 0;
}
Explicación:
El programa sigue pidiendo números al usuario hasta que se introduce un 0. Es un caso típico de uso para while
, donde no sabemos cuántas veces se repetirá.
Diferencias clave entre for
y while
Característica | for | while |
---|---|---|
Uso típico | Repeticiones con un número definido | Condición depende del contexto |
Declaración de control | Incluida en una sola línea | Declaración suele estar separada |
Legibilidad | Más conciso para ciclos contados | Más flexible pero menos compacto |
Puede omitirse todo | Sí (aunque poco recomendable) | No |
Precaución: Bucles infinitos
Un bucle infinito ocurre cuando la condición nunca se vuelve falsa. Esto puede causar que el programa no termine o consuma muchos recursos.
Ejemplo de bucle infinito:
while (1) {
// Esto se ejecuta para siempre
}
Este tipo de bucles pueden usarse en sistemas embebidos o juegos, pero deben controlarse cuidadosamente con una condición de salida interna (break
), esto lo veremos más adelante.
Bucle do...while
en C
El bucle do...while
es una variante del bucle while
, con una diferencia muy importante: evalúa la condición al final del ciclo, no al principio. Esto garantiza que el código dentro del bucle se ejecute al menos una vez, incluso si la condición es falsa desde el principio.
Sintaxis
do {
// Código a ejecutar
} while (condición);
- El bloque dentro de
do { ... }
se ejecuta una primera vez sin verificar la condición. - Después de esa ejecución, se evalúa la condición en
while (condición)
. - Si la condición es verdadera, se repite el ciclo.
- Si es falsa, el bucle termina.
@Tip: La sentencia
while
termina con punto y coma;
, lo cual distingue a este bucle de los demás.
Vamos a verlo con un ejemplo
#include <stdio.h>
int main() {
int numero = 0;
do {
printf("Este mensaje se muestra al menos una vez.\n");
} while (numero != 0);
return 0;
}
Explicación:
- Aunque la condición
numero != 0
es falsa desde el inicio, el mensaje se imprime una vez porque el cuerpo del bucle se ejecuta antes de verificar la condición.
Otro ejemplo de como leer hasta que el usuario introduzca una contraseña correcta:
#include <stdio.h>
#include <string.h>
int main() {
char password[20];
do {
printf("Introduce la contraseña: ");
scanf("%19s", password); // Limitamos a 19 caracteres para evitar desbordamiento
} while (strcmp(password, "clave123") != 0);
printf("¡Contraseña correcta!\n");
return 0;
}
Explicación:
- El programa siempre pide una contraseña al menos una vez.
- Luego compara con
"clave123"
mediante la funciónstrcmp()
. - El bucle continúa mientras la contraseña sea incorrecta.
Hagamos otro programa para validar entrada de número entre 1 y 10, sería así:
#include <stdio.h>
int main() {
int numero;
do {
printf("Introduce un número entre 1 y 10: ");
scanf("%d", &numero);
} while (numero < 1 || numero > 10);
printf("Número válido: %d\n", numero);
return 0;
}
Explicación:
- El bucle asegura que el número ingresado esté en el rango entre 1 y 10.
- Si el usuario ingresa un número fuera del rango, se repite la petición.
Cuándo usar do...while
Caso típico | Justificación |
---|---|
Mostrar un menú que debe aparecer al menos una vez | El menú necesita mostrarse antes de evaluar |
Validar datos de entrada del usuario | Se deben pedir datos al menos una vez |
Bucle que depende de eventos que suceden después de una acción | La condición solo puede saberse tras ejecutarse |
Importante
- Si olvidas actualizar una variable dentro del bucle o la condición nunca se vuelve falsa, puedes generar un bucle infinito.
- Es imprescindible tener claro qué condición terminará el bucle y asegurar que el usuario o el programa puedan influir en ella.
Comparativa entre bucles
Tipo de bucle | ¿Evalúa antes? | ¿Se ejecuta al menos una vez? | Ideal para… |
---|---|---|---|
for | ✅ Sí | ❌ No (si condición es falsa) | Iteraciones conocidas |
while | ✅ Sí | ❌ No (si condición es falsa) | Condición controlada externamente |
do...while | ❌ No | ✅ Sí | Menús, validaciones, ejecución inicial |
Sentencia switch
en C
La instrucción switch
es una estructura de control de flujo condicional múltiple que permite ejecutar diferentes bloques de código en función del valor de una única expresión. Es especialmente útil cuando necesitas comparar una variable contra varios valores posibles.
Se considera una alternativa más legible al uso de múltiples sentencias if...else if...else
cuando todas las condiciones se basan en comparar una misma variable con distintos valores constantes.
Sintaxis general
switch (expresión) {
case valor1:
// Código si expresión == valor1
break;
case valor2:
// Código si expresión == valor2
break;
...
default:
// Código si no se cumple ningún caso anterior
}
Elementos de la sentencia switch:
expresión
: debe ser de tipo entero (int
,char
,enum
, etc.). No se permiten expresionesfloat
nidouble
.case valor:
: compara el valor de la expresión convalor
. Si coinciden, se ejecuta ese bloque.break;
: interrumpe la ejecución delswitch
tras ejecutar un caso. Es fundamental para evitar que se ejecuten los siguientes casos (comportamiento llamado fall-through).default:
: es opcional. Se ejecuta si ningún caso anterior coincide con la expresión.
Veamos un ejemplo básico para implementar un menú de opciones.
#include <stdio.h>
int main() {
int opcion;
printf("Menú:\n");
printf("1. Nuevo archivo\n");
printf("2. Abrir archivo\n");
printf("3. Guardar archivo\n");
printf("Selecciona una opción: ");
scanf("%d", &opcion);
switch (opcion) {
case 1:
printf("Has seleccionado: Nuevo archivo\n");
break;
case 2:
printf("Has seleccionado: Abrir archivo\n");
break;
case 3:
printf("Has seleccionado: Guardar archivo\n");
break;
default:
printf("Opción no válida.\n");
}
return 0;
}
Explicación:
- Según el número introducido por el usuario, se ejecuta un bloque diferente.
- Si introduce un número fuera del 1 al 3, se activa el
default
.
Vamos a ver cómo utilizar witch con valores tipo char mediante un sistema que identifique el día de la semana.
#include <stdio.h>
int main() {
char dia;
printf("Introduce una letra (L, M, X, J, V): ");
scanf(" %c", &dia); // Ojo: el espacio antes de %c consume saltos de línea anteriores
switch (dia) {
case 'L':
printf("Lunes\n");
break;
case 'M':
printf("Martes\n");
break;
case 'X':
printf("Miércoles\n");
break;
case 'J':
printf("Jueves\n");
break;
case 'V':
printf("Viernes\n");
break;
default:
printf("Letra inválida\n");
}
return 0;
}
Fall-through: ejecutar varios casos seguidos
Si omites break
, la ejecución continuará en los siguientes case
, incluso si ya se ha encontrado uno válido. Esto se conoce como fall-through, y aunque generalmente se evita, puede ser útil en ciertos escenarios.
#include <stdio.h>
int main() {
int nota = 5;
switch (nota) {
case 10:
case 9:
printf("Sobresaliente\n");
break;
case 8:
case 7:
printf("Notable\n");
break;
case 6:
printf("Bien\n");
break;
case 5:
printf("Suficiente\n");
break;
default:
printf("Insuficiente\n");
}
return 0;
}
Explicación:
- Las notas 10 y 9 entran en el primer bloque (Sobresaliente).
- Las notas 8 y 7 entran en el segundo bloque (Notable).
- Se reutilizan los mismos bloques para valores similares sin repetir código.
Limitaciones de switch
en C
- Como hemos indicado anteriormente, solo permite evaluar tipos enteros (
int
,char
,enum
). No sirve parafloat
,double
ni cadenas de texto. - No puedes usar rangos (
case 1..5:
no es válido). - La expresión debe evaluarse a un valor constante. No se admiten variables como condiciones de caso.
Resumen comparativo con if...else
Característica | switch | if...else |
---|---|---|
Tipo de expresión | Entero (int, char, enum) | Cualquier expresión lógica |
Comparación múltiple | ✅ Excelente para múltiples valores | ✅ También sirve, pero menos legible |
Uso con rangos o condiciones | ❌ No es posible | ✅ Sí |
Claridad y legibilidad | ✅ Alta (si se compara la misma var) | Puede volverse complejo con muchos casos |
3.3 Control de flujo: break
, continue
y goto
En C, estas sentencias especiales permiten alterar el flujo natural de ejecución de un programa dentro de bucles o estructuras de control. Aunque deben usarse con responsabilidad para mantener la legibilidad del código, son muy útiles en situaciones específicas.
break
La sentencia break
interrumpe la ejecución de un bucle o un switch
. Cuando el programa encuentra un break
, sale inmediatamente del bucle o del bloque switch
que lo contiene.
Usos típicos:
- Para salir anticipadamente de un bucle
for
,while
odo...while
. - Para finalizar la ejecución de un caso en una estructura
switch
.
Veamoslo con un ejemplo dentro de un bucle, vamos a imprimir los número del 1 al 10 pero cuando llegue al 5 salimos sin imprimir el resto.
#include <stdio.h>
int main() {
int i;
for (i = 1; i <= 10; i++) {
if (i == 5) {
break; // Sal del bucle cuando i sea 5
}
printf("i = %d\n", i);
}
return 0;
}
Resultado:
i = 1
i = 2
i = 3
i = 4
Explicación:
- El bucle termina prematuramente cuando
i
vale 5.
continue
La sentencia continue
salta el resto del código dentro de la iteración actual y continúa con la siguiente iteración del bucle. No interrumpe el bucle, solo omite el código posterior al continue
en esa vuelta.
Ejemplo:
#include <stdio.h>
int main() {
int i;
for (i = 1; i <= 5; i++) {
if (i == 3) {
continue; // Salta la iteración cuando i es 3
}
printf("i = %d\n", i);
}
return 0;
}
Resultado:
i = 1
i = 2
i = 4
i = 5
Explicación:
- Cuando
i == 3
, se ejecutacontinue
y se omite elprintf
, pasando a la siguiente vuelta del bucle.
goto
La sentencia goto
salta la ejecución a una etiqueta específica ubicada en otra parte del programa. Es una forma de control incondicional del flujo.
Aunque la tenemos disponible, su uso está desaconsejado porque puede dificultar la lectura y mantenimiento del código si se usa sin cuidado. En la programación actual, se prefiere evitarla y recurrir a funciones o estructuras más claras.
Sintaxis:
goto etiqueta;
// ...
etiqueta:
// Código al que se salta
Quedaría así en un programa:
#include <stdio.h>
int main() {
int i = 1;
while (i <= 10) {
if (i == 5)
goto fin;
printf("i = %d\n", i);
i++;
}
fin:
printf("Has saltado a la etiqueta 'fin'\n");
return 0;
}
Resultado:
i = 1
i = 2
i = 3
i = 4
Has saltado a la etiqueta 'fin'
Explicación:
- Cuando
i == 5
, el programa salta a la etiquetafin
, interrumpiendo el bucle.
Cuándo evitar goto
Aunque el lenguaje lo permite, usar goto
puede llevarnos a lo que en programación se llama «código espagueti», donde es difícil seguir el flujo lógico. Solo en situaciones muy específicas (como salir de múltiples bucles anidados o manejar errores de forma estructurada en sistemas embebidos) puede estar justificado.
Comparativa
Sentencia | Significado | Uso Principal |
---|---|---|
break | Sale inmediatamente del bucle o switch | Interrupción anticipada |
continue | Salta al siguiente ciclo del bucle | Omitir una iteración |
goto | Salta a una etiqueta específica del código | Control de flujo incondicional |
Conclusión
En este capítulo hemos aprendido uno de los pilares fundamentales de la programación: el control del flujo de ejecución. Mediante estructuras condicionales como if
, else
y switch
, hemos aprendido a tomar decisiones en los programas. Por otro lado, hemos visto que con los bucles for
, while
y do...while
podemos repetir bloques de código tantas veces como lo necesitemos. Además, las sentencias especiales break
, continue
y goto
te permite modificar el flujo estándar de estas estructuras, aunque deben usarse con cautela para mantener un código limpio y fácil de entender. Pasemos a la parte práctica con unos ejercicios.
Ejercicio 1: Números pares del 1 al 20 (usando for
y continue
)
Enunciado:
Escribe un programa que imprima todos los números pares entre 1 y 20. Utiliza un bucle for
y la sentencia continue
para omitir los números impares.
for
y continue
)Enunciado:
Escribe un programa que imprima todos los números pares entre 1 y 20. Utiliza un bucle
for
y la sentencia continue
para omitir los números impares.Código:
#include <stdio.h>
int main() {
int i;
for (i = 1; i <= 20; i++) {
if (i % 2 != 0) {
continue; // Si el número es impar, lo saltamos
}
printf("%d ", i);
}
return 0;
}
Explicación:
- El bucle recorre del 1 al 20.
- Si el número actual no es divisible entre 2 (
i % 2 != 0
), se ejecutacontinue
y no se imprime. - Solo se imprimen los números pares.
Ejercicio 2: Suma de positivos hasta número negativo (usando while
y break
)
Enunciado:
Escribe un programa que lea números enteros del usuario y los sume hasta que se introduzca un número negativo. Cuando esto ocurra, el programa debe finalizar mostrando la suma total.
while
y break
)Enunciado:
Escribe un programa que lea números enteros del usuario y los sume hasta que se introduzca un número negativo. Cuando esto ocurra, el programa debe finalizar mostrando la suma total.
Código:
#include <stdio.h>
int main() {
int num, suma = 0;
while (1) { // Bucle infinito hasta encontrar número negativo
printf("Introduce un número (negativo para salir): ");
scanf("%d", &num);
if (num < 0) {
break; // Salir si el número es negativo
}
suma += num;
}
printf("La suma total es: %d\n", suma);
return 0;
}
Explicación:
- Se utiliza un bucle
while (1)
para repetir indefinidamente. - Si el usuario introduce un número negativo, se ejecuta
break
y se finaliza el bucle. - Se acumulan los números positivos en la variable
suma
.
Ejercicio 3: Menú de operaciones con switch
Enunciado:
Escribe un programa que presente un menú al usuario con tres opciones: sumar dos números, restar dos números o salir. Según la opción elegida, el programa debe realizar la operación correspondiente usando switch
.
switch
Enunciado:
Escribe un programa que presente un menú al usuario con tres opciones: sumar dos números, restar dos números o salir. Según la opción elegida, el programa debe realizar la operación correspondiente usando
switch
.Código:
#include <stdio.h>
int main() {
int opcion, a, b;
printf("Menú de operaciones:\n");
printf("1. Sumar dos números\n");
printf("2. Restar dos números\n");
printf("3. Salir\n");
printf("Elige una opción: ");
scanf("%d", &opcion);
switch (opcion) {
case 1:
printf("Introduce dos números: ");
scanf("%d %d", &a, &b);
printf("Resultado: %d\n", a + b);
break;
case 2:
printf("Introduce dos números: ");
scanf("%d %d", &a, &b);
printf("Resultado: %d\n", a - b);
break;
case 3:
printf("Saliendo del programa...\n");
break;
default:
printf("Opción no válida\n");
}
return 0;
}
Explicación:
- Se usa un
switch
para ejecutar una operación distinta según la opción ingresada. - Las opciones válidas son 1 (suma), 2 (resta) y 3 (salir).
- Se manejan errores con
default
si el usuario introduce una opción no válida.
Bibliografía del tutorial de C/C++.
- C/C++. Curso de programación. Autor: Miguel Angel Acera (Editorial: Anaya Multimedia)
- C/C++. Curso de programación. Autor: Francisco José Ceballos (Editorial: RA-MA)
- Un recorrido por C++. Autor Bjarne Stroustrup (Editorial: Anaya Multimedia)
- 115 Ejercicios resueltos de programación C++. Autor Jorge Fernando Betancourt e Inma Yolanda Polanco (Editorial: RA-MA)