Operador break

El operador break está pensado para terminar de forma anticipada de los operadores cíclicos for, while, do, así como a la salida de la sentencia de selección switch. El operador sólo puede aplicarse dentro de las sentencias especificadas y sólo afecta a la que contiene inmediatamente a break si hay varias anidadas. Tras procesar la sentencia break, la ejecución del programa continúa hasta la sentencia siguiente al operador cíclico interrumpido o switch.

La sintaxis es muy sencilla: la palabra clave break y un punto y coma:

break ;

Cuando se utiliza dentro de bucles, break suele implementarse en una de las ramas del operador condicional if/else.

Considere un script que imprime el contador de tiempo actual del sistema una vez por segundo, pero no más de 100 veces. Contempla la gestión de la interrupción del proceso por parte del usuario; para ello, la función IsStopped se sondea en el operador condicional if y su sentencia dependiente contiene break (StmtJumpBreak.mq5).

int count = 0;
while(++count < 100)
{
   Comment(GetTickCount());
   Sleep(1000);
   if(IsStopped())
   {
      Print("Terminated by user");
      break;
   }
}

En el siguiente ejemplo se rellena una matriz diagonal con una tabla de multiplicar (la esquina superior derecha permanecerá rellena de ceros).

int a[10][10] = {0};
for(int i = 0i < 10; ++i)
{
   for(int j = 0j < 10; ++j)
   {
      if(j > i)
         break;
      a[i][j] = (i + 1) * (j + 1);
   }
}
ArrayPrint(a);

Cuando la variable del bucle interno j es mayor que la variable del bucle externo i, la sentencia break rompe el bucle interno. Por supuesto, esta no es la mejor manera de rellenar la matriz diagonalmente; sería más fácil hacer un bucle sobre j de 0 a i sin ningún break, pero aquí demuestra la presencia de construcciones equivalentes con break y sin break.

Aunque las cosas pueden no ser tan obvias en proyectos de producción, se recomienda evitar el operador break siempre que sea posible y sustituirlo por variables adicionales (por ejemplo, una variable booleana con un nombre needAbreak «revelador»), que deberían utilizarse en expresiones terminales en los encabezados de bucle para romperlas de la forma estándar.

Imagine que se utilizan dos bucles anidados para encontrar caracteres duplicados en una cadena. El primer bucle actualiza secuencialmente cada carácter de la cadena y el segundo recorre los caracteres restantes (hacia la derecha).

string s = "Hello, " + Symbol();
ushort d = 0;
const int n = StringLen(s);
for(int i = 0i < n; ++i)
{
   for(int j = i + 1j < n; ++j)
   {
      if(s[i] == s[j])
      {
         d = s[i];
         break;
      }
   }
}

Si los caracteres de las posiciones i y j coinciden, recuerde el carácter duplicado y salga del bucle mediante break.

Se podría dar por sentado que la variable d debería contener la letra 'l' tras la ejecución de este fragmento. Sin embargo, si coloca el script en el instrumento más popular «EURUSD», la respuesta será 'U'. El caso es que break sólo rompe el bucle interno, y tras encontrar el primer duplicado ('ll' en la palabra «Hola»), el bucle continúa en i. Por lo tanto, para salir de varios bucles anidados a la vez, deben tomarse medidas adicionales.

La forma más popular es incluir en la condición del bucle exterior (o de todos los bucles exteriores) una variable que se rellena en el bucle interior. En nuestro caso, ya existe una variable de este tipo: d.

for(int i = 0i < n && d == 0; ++i)
{
   for(int j = i + 1j < n; ++j)
   {
      if(s[i] == s[j])
      {
         d = s[i];
         break;
      }
   }
}

Al comprobar que d es igual a 0 se detendrá el bucle exterior después de encontrar el primer duplicado. Pero la misma comprobación puede añadirse al bucle interno, lo que elimina la necesidad de utilizar break.

for(int i = 0i < n && d == 0; ++i)
{
   for(int j = i + 1j < n && d == 0; ++j)
   {
      if(s[i] == s[j])
      {
         d = s[i];
      }
   }
}