Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Regla 0x100Dh: Prohibición de condiciones de parada compuestas complejas en lazos for

Estructuras de control y flujo (0x10XX)

Universidad Nacional de Río Negro

0x100Dh: Prohibición de condiciones de parada compuestas complejas en lazos for

Enunciado normativo

La condición de un for DEBE ser una única comprobación de cota o rango (por ejemplo i < n). Si el corte del lazo requiere combinar condiciones lógicas con && o ||, DEBE usarse un lazo while.

¿Por qué existe esta regla?

El problema

La fortaleza del for es que su encabezado se lee de un vistazo: dónde empieza, hasta dónde llega y cómo avanza. Cuando la condición pasa a ser i < n && !encontrado && limite > 0, ese vistazo ya no alcanza: el encabezado esconde varias causas de corte y el lector debe evaluar cómo interactúan.

Peor aún, la condición compuesta mezcla dos naturalezas: una cota estructural (i < n) y un estado dinámico (!encontrado). Separarlas ayuda a razonar: el for recorre el rango y el while espera el evento.

Consecuencias de violarla

Tipo de consecuenciaEfecto concreto
LegibilidadVarias condiciones de corte compiten en una sola línea.
Bug lógicoEl cortocircuito de && puede ocultar un acceso fuera de rango si se reordena.
MantenibilidadCambiar una condición obliga a tocar el encabezado y el cuerpo.
DuplicaciónLa condición dinámica se reescribe también dentro del cuerpo.

Fundamento en el estándar y en la cátedra

ISO/IEC 9899:2011 §6.8.5.3 admite cualquier expresión en la condición del for; la restricción es de diseño. La cátedra la adopta para reforzar el uso comunicativo de cada lazo (ver 0x1003h: Utilizá el lazo for para iteraciones con rango o contador definido y while para lazos controlados por condiciones lógicas) y para prevenir el off-by-one del antipatrón asociado. Se complementa con 0x1004h: Las condiciones complejas deben simplificarse o comentarse y 0x1013h: Detector de expresiones booleanas complejas sin paréntesis aclaratorios.

Alcance y excepciones

Ejemplos exhaustivos

❌ Contraejemplo 1 — búsqueda con triple condición

for (int i = 0; i < n && !encontrado && limite > 0; i++)
{
    if (valores[i] == buscado)
    {
        encontrado = true;
    }
    limite--;
}

Por qué falla: el encabezado mezcla una cota de arreglo con un estado y un presupuesto. Si se reordena &&, un acceso a valores[i] puede quedar sin la protección de i < n.

❌ Contraejemplo 2 — for con corte por valor leído

for (int n = leer(); n != 0; n = leer())
{
    procesar(n);
}

Por qué falla: no hay contador ni rango; el corte depende del dato. El for obliga a duplicar la lectura en dos cláusulas y no comunica un recorrido.

✅ Ejemplo conforme 1 — for con cota simple

for (size_t i = 0; i < cantidad; i++)
{
    total += valores[i];
}

Una única comprobación de cota; el recorrido completo se entiende desde el encabezado.

✅ Ejemplo conforme 2 — while para el corte dinámico

size_t i = 0;
bool encontrado = false;
while (i < cantidad && !encontrado)
{
    if (valores[i] == buscado)
    {
        encontrado = true;
    }
    i++;
}

El while es el lazo natural para una condición lógica; el avance queda en el cuerpo porque ahora sí es parte de la lógica, no de una cota fija.

⚠️ Casos límite

Cómo detectarla

HerramientaComandoSeñal
gaffgaff check archivo.cRegla 0x100Dh: condición de for compuesta.
gccgcc -Wall -WextraNo la detecta; es una regla de diseño.
Revisión manualEncabezado de for con && o `

Checklist de autocontrol

Reglas relacionadas

Antipatrón: Posible error off-by-one en condición de parada de bucle

Síntoma en el código del estudiante

La condición del for usa <= sobre un arreglo, o compara contra la dimensión en lugar de contra el último índice:

int arr[10];
for (int i = 0; i <= 10; i++)
{
    arr[i] = 0;
}

Diagnóstico

Mecanismo del defecto

Un arreglo de tamaño N declarado int arr[N] tiene índices válidos de 0 a N - 1 (ISO/IEC 9899:2011 §6.5.2.1). La condición i <= N incluye i == N, que es exactamente un acceso fuera del arreglo. El error clásico es confundir “la dimensión” con “el último índice válido”.

Consecuencia observable

El programa escribe (o lee) un elemento más allá del final: corrompe la variable contigua, falla con SIGSEGV o pasa desapercibido según el diseño de memoria. En arreglos locales suele pisar otra variable; en el heap, los metadatos del asignador. Es un comportamiento indefinido.

Fundamento en el estándar C11

ISO/IEC 9899:2011 §6.5.2.1 define la indexación E1[E2] como *((E1)+(E2)) y §6.5.6 la aritmética de punteros. Acceder a arr[N] construye un puntero un elemento más allá del final del objeto, lo que no está permitido. La cátedra exige la cota estricta i < N y recomienda size_t para índices (regla 0x3010h).

Corrección idiomática

❌ Código con el antipatrón
int arr[10];
for (int i = 0; i <= 10; i++)
{
    arr[i] = 0;
}
✅ Código refactorizado
int arr[10];
for (size_t i = 0; i < 10; i++)
{
    arr[i] = 0;
}

La cota i < 10 recorre exactamente los índices 0..9. Usar size_t mantiene el índice sin signo y permite compararlo contra sizeof arr / sizeof arr[0].

Alternativa robusta:

int arr[10];
size_t n = sizeof(arr) / sizeof(arr[0]);
for (size_t i = 0; i < n; i++)
{
    arr[i] = 0;
}

Errores típicos al compilar o ejecutar

En ejecución, con -fsanitize=address:
ERROR: AddressSanitizer: stack-buffer-overflow on address ... READ of size 4
    #0 in main

Sin sanitizador, el programa "funciona" pero corrompe la memoria contigua;
el fallo aparece luego, lejos de la causa.

Checklist de verificación

Reglas relacionadas

Antipatrón: Invocación a strlen() en condición de parada de bucle for

Síntoma en el código del estudiante

La condición del for llama a strlen (u otra función costosa) en cada iteración:

for (size_t i = 0; i < strlen(s); i++)
{
    procesar(s[i]);
}

Diagnóstico

Mecanismo del defecto

strlen(s) recorre la cadena entera contando caracteres hasta el '\0' (ISO/IEC 9899:2011 §7.24.6.3). Al estar en la condición, se evalúa una vez por iteración; el costo total es n recorridos de n caracteres, es decir O(n²). La función no se llama una vez sino n veces.

Consecuencia observable

El programa funciona pero se degrada de forma notable con cadenas largas. Para una cadena de 100 000 caracteres, el lazo hace ~5 000 millones de comparaciones en lugar de 100 000. En un ejercicio pequeño casi no se nota; en una entrega con volumen es un problema de rendimiento medible.

Fundamento en el estándar C11

ISO/IEC 9899:2011 §7.24.6.3 define strlen sin garantía de memoización: cada llamada recorre la cadena. El estándar no prohíbe usarla en la condición, pero la cátedra exige sacar la evaluación invariante del lazo. Se relaciona con 0x100Dh: Prohibición de condiciones de parada compuestas complejas en lazos for y con la separación de la condición de las operaciones costosas.

Corrección idiomática

❌ Código con el antipatrón
for (size_t i = 0; i < strlen(s); i++)
{
    procesar(s[i]);
}
✅ Código refactorizado
size_t len = strlen(s);
for (size_t i = 0; i < len; i++)
{
    procesar(s[i]);
}

La longitud se calcula una vez y se guarda en len; la condición solo compara dos enteros. El costo baja a O(n) y el código es más fácil de leer.

Errores típicos al compilar o ejecutar

No hay error de compilación ni advertencia.

Con cadenas cortas el tiempo es imperceptible. Con cadenas de 100000
caracteres, el bucle tarda cientos de milisegundos en lugar de microsegundos.
Un perfil con perf o gprof muestra strlen en el tope del consumo.

Checklist de verificación

Reglas relacionadas