Control condicional
Las estructuras condicionales permiten que nuestros programas tomen decisiones basadas en el valor de expresiones específicas. En C, disponemos de varias herramientas para implementar lógica condicional que van desde la simple evaluación de condiciones hasta la selección entre múltiples alternativas.
La toma de decisiones es fundamental en cualquier programa. Un programa que siempre ejecute las mismas instrucciones en el mismo orden tiene utilidad limitada. Los condicionales nos permiten crear programas que respondan de forma diferente según las circunstancias.
Estructura if básica
La estructura condicional más fundamental es la declaración if
. Su sintaxis básica evalúa una expresión y ejecuta un bloque de código únicamente si dicha expresión es verdadera:
#include <stdio.h>
int main() {
int edad = 18;
// Condicional simple
if (edad >= 18) {
printf("Eres mayor de edad\n");
}
return 0;
}
Es importante recordar que en C, cualquier valor diferente de cero se considera verdadero, mientras que el valor cero se considera falso. Esta característica nos permite escribir condiciones concisas:
#include <stdio.h>
int main() {
int numero = 5;
// Ambas condiciones son equivalentes
if (numero != 0) {
printf("El número no es cero\n");
}
if (numero) { // Más conciso
printf("El número no es cero\n");
}
return 0;
}
Estructura if-else
Cuando necesitamos ejecutar código alternativo si la condición no se cumple, utilizamos la estructura if-else
. Esta construcción garantiza que siempre se ejecute exactamente uno de los dos bloques:
#include <stdio.h>
int main() {
int temperatura = 25;
if (temperatura > 30) {
printf("Hace calor\n");
} else {
printf("La temperatura es agradable\n");
}
return 0;
}
Cadenas if-else if
Para evaluar múltiples condiciones en secuencia, podemos encadenar declaraciones else if
. El programa evaluará cada condición en orden y ejecutará el primer bloque cuya condición sea verdadera:
#include <stdio.h>
int main() {
int calificacion = 85;
if (calificacion >= 90) {
printf("Excelente\n");
} else if (calificacion >= 80) {
printf("Muy bien\n");
} else if (calificacion >= 70) {
printf("Bien\n");
} else if (calificacion >= 60) {
printf("Suficiente\n");
} else {
printf("Insuficiente\n");
}
return 0;
}
Operador ternario
Para asignaciones condicionales simples, C proporciona el operador ternario ?:
, que es una forma compacta de escribir una estructura if-else básica:
#include <stdio.h>
int main() {
int a = 10, b = 20;
int mayor;
// Usando if-else tradicional
if (a > b) {
mayor = a;
} else {
mayor = b;
}
// Equivalente con operador ternario
mayor = (a > b) ? a : b;
printf("El mayor es: %d\n", mayor);
return 0;
}
Estructura switch
Cuando necesitamos comparar una variable contra múltiples valores constantes específicos, la estructura switch
ofrece una alternativa más legible y eficiente que una cadena de if-else if
:
#include <stdio.h>
int main() {
int dia = 3;
switch (dia) {
case 1:
printf("Lunes\n");
break;
case 2:
printf("Martes\n");
break;
case 3:
printf("Miércoles\n");
break;
case 4:
printf("Jueves\n");
break;
case 5:
printf("Viernes\n");
break;
case 6:
case 7:
printf("Fin de semana\n");
break;
default:
printf("Día inválido\n");
break;
}
return 0;
}
La palabra clave **break**
es crucial en las estructuras switch. Sin ella, la ejecución continuará hacia el siguiente caso, lo que se conoce como "fall-through". Este comportamiento puede ser útil intencionalmente, como en el ejemplo anterior donde los casos 6 y 7 comparten la misma lógica.
Expresiones booleanas complejas
C permite combinar múltiples condiciones usando operadores lógicos. Los operadores más comunes son:
**&&**
(AND lógico): verdadero solo si ambas condiciones son verdaderas**||**
(OR lógico): verdadero si al menos una condición es verdadera**!**
(NOT lógico): invierte el valor de la condición
#include <stdio.h>
int main() {
int edad = 25;
int salario = 30000;
// AND lógico
if (edad >= 18 && salario >= 25000) {
printf("Califica para el préstamo\n");
}
// OR lógico
if (edad < 18 || edad > 65) {
printf("Descuento especial aplicable\n");
}
// NOT lógico
if (!(edad < 18)) { // Equivale a edad >= 18
printf("Es mayor de edad\n");
}
return 0;
}
Condiciones anidadas
Es posible anidar estructuras condicionales dentro de otras para crear lógica más compleja. Sin embargo, es importante mantener la legibilidad del código:
#include <stdio.h>
int main() {
int hora = 14;
int dia_semana = 2; // 1=Lunes, 7=Domingo
if (dia_semana >= 1 && dia_semana <= 5) {
// Es día laborable
if (hora >= 9 && hora <= 17) {
printf("Horario de oficina\n");
} else {
printf("Fuera del horario de oficina\n");
}
} else {
// Es fin de semana
printf("Es fin de semana\n");
}
return 0;
}
Mejores prácticas
Al trabajar con estructuras condicionales, es importante seguir ciertas prácticas que mejoran la legibilidad y mantenibilidad del código:
- 1. Usa siempre llaves incluso para declaraciones de una sola línea:
// Evita esto
if (condicion)
printf("Mensaje\n");
// Prefiere esto
if (condicion) {
printf("Mensaje\n");
}
- 2. Compara explícitamente cuando sea necesario para mayor claridad:
// Para punteros
if (ptr != NULL) { /* código */ }
// Para comparaciones con cero
if (contador == 0) { /* código */ }
- 3. Ordena las condiciones de más probable a menos probable en cadenas
if-else if
para mejorar el rendimiento:
// Si los valores altos son más comunes
if (valor > 1000) {
// Caso más frecuente primero
} else if (valor > 100) {
// Segundo más frecuente
} else {
// Caso menos frecuente
}
Control iterativo
Las estructuras iterativas permiten ejecutar un bloque de código de forma repetida mientras se cumple una condición específica. Este mecanismo es esencial para automatizar tareas repetitivas, procesar conjuntos de datos y crear programas que puedan manejar volúmenes variables de información.
En C disponemos de tres tipos principales de bucles: while
, do-while
y for
. Cada uno tiene características específicas que los hacen más apropiados para diferentes situaciones de programación.
Bucle while
El bucle **while**
evalúa una condición antes de ejecutar el bloque de código. Si la condición es falsa desde el principio, el código dentro del bucle nunca se ejecuta:
#include <stdio.h>
int main() {
int contador = 0;
while (contador < 5) {
printf("Iteración número: %d\n", contador);
contador++; // Importante: actualizar la variable de control
}
printf("El bucle ha terminado\n");
return 0;
}
La actualización de la variable de control dentro del bucle es crucial para evitar bucles infinitos. Sin ella, la condición nunca cambiará y el programa se ejecutará indefinidamente.
Bucle do-while
El bucle **do-while**
ejecuta el bloque de código al menos una vez antes de evaluar la condición. Esto lo convierte en la elección perfecta cuando necesitamos que el código se ejecute mínimo una vez:
#include <stdio.h>
int main() {
int numero;
do {
printf("Introduce un número positivo: ");
scanf("%d", &numero);
if (numero <= 0) {
printf("El número debe ser positivo\n");
}
} while (numero <= 0);
printf("Gracias, has introducido: %d\n", numero);
return 0;
}
Este ejemplo demuestra un caso típico donde **do-while**
es superior a while
: validación de entrada de usuario, donde necesitamos pedir la entrada al menos una vez.
Bucle for
El bucle **for**
es ideal cuando conocemos de antemano el número de iteraciones o cuando necesitamos un contador específico. Su sintaxis compacta incluye inicialización, condición y actualización en una sola línea:
#include <stdio.h>
int main() {
// Bucle for básico
for (int i = 0; i < 10; i++) {
printf("%d ", i);
}
printf("\n");
// Bucle for con incremento personalizado
for (int i = 2; i <= 20; i += 2) {
printf("%d ", i); // Números pares del 2 al 20
}
printf("\n");
return 0;
}
La declaración de la variable i
dentro del bucle for
es una práctica moderna que limita su alcance al bucle, mejorando la legibilidad y evitando conflictos de nombres.
Bucles anidados
Los bucles anidados permiten crear estructuras de repetición más complejas, útiles para procesar matrices, generar patrones o realizar operaciones multidimensionales:
#include <stdio.h>
int main() {
// Tabla de multiplicar del 1 al 5
for (int i = 1; i <= 5; i++) {
printf("Tabla del %d:\n", i);
for (int j = 1; j <= 10; j++) {
printf("%d x %d = %d\n", i, j, i * j);
}
printf("\n"); // Línea en blanco entre tablas
}
return 0;
}
Sentencias de control de flujo
C proporciona sentencias especiales para modificar el comportamiento normal de los bucles:
1 - Sentencia **break**
:
La sentencia break
termina inmediatamente el bucle más interno que la contiene:
#include <stdio.h>
int main() {
for (int i = 1; i <= 10; i++) {
if (i == 6) {
break; // Sale del bucle cuando i es 6
}
printf("%d ", i);
}
printf("\nBucle terminado\n");
return 0;
}
2 - Sentencia **continue**
:
La sentencia continue
salta a la siguiente iteración del bucle, omitiendo el resto del código en la iteración actual:
#include <stdio.h>
int main() {
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // Salta los números pares
}
printf("%d ", i); // Solo imprime números impares
}
printf("\n");
return 0;
}
Casos de uso prácticos
Procesamiento de arrays:
#include <stdio.h>
int main() {
int numeros[] = {10, 25, 30, 45, 50};
int suma = 0;
int tamaño = sizeof(numeros) / sizeof(numeros[0]);
// Calcular la suma de todos los elementos
for (int i = 0; i < tamaño; i++) {
suma += numeros[i];
}
printf("La suma es: %d\n", suma);
return 0;
}
Búsqueda en un conjunto de datos:
#include <stdio.h>
int main() {
int numeros[] = {15, 23, 8, 42, 16, 7, 31};
int objetivo = 42;
int encontrado = 0;
int tamaño = sizeof(numeros) / sizeof(numeros[0]);
for (int i = 0; i < tamaño; i++) {
if (numeros[i] == objetivo) {
printf("Número %d encontrado en la posición %d\n", objetivo, i);
encontrado = 1;
break; // Terminar la búsqueda al encontrarlo
}
}
if (!encontrado) {
printf("Número %d no encontrado\n", objetivo);
}
return 0;
}
Mejores prácticas para bucles
1 - Inicializa siempre las variables de control:
// Correcto
int i = 0;
while (i < 10) {
printf("%d\n", i);
i++;
}
// Incorrecto - variable sin inicializar
int j; // Valor indefinido
while (j < 10) {
printf("%d\n", j);
j++;
}
2 - Evita modificar la variable de control dentro del bucle for
a menos que sea necesario:
// Preferible
for (int i = 0; i < 10; i++) {
printf("%d ", i);
}
// Evitar
for (int i = 0; i < 10; i++) {
printf("%d ", i);
i += 2; // Modificación adicional confusa
}
3 - Usa nombres descriptivos para variables de bucles anidados:
// Claro y descriptivo
for (int fila = 0; fila < 3; fila++) {
for (int columna = 0; columna < 4; columna++) {
printf("[%d,%d] ", fila, columna);
}
printf("\n");
}
4 - Prefiere bucles **for**
cuando el número de iteraciones es conocido:
// Mejor para contadores fijos
for (int i = 0; i < 100; i++) {
// procesamiento
}
// Mejor para condiciones dinámicas
while (usuario_activo && datos_disponibles) {
// procesamiento
}
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en C
Documentación oficial de C
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, C es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de C
Explora más contenido relacionado con C y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender y utilizar estructuras condicionales básicas como if, if-else y switch.
- Aplicar operadores lógicos para crear expresiones booleanas complejas.
- Implementar bucles iterativos: while, do-while y for.
- Manejar sentencias de control de flujo como break y continue.
- Seguir buenas prácticas para mejorar la legibilidad y mantenimiento del código.