una todas tipos significado sentencia parametros llamar las funciones funcion ejemplos con como c++ loops label nested-loops

todas - tipos de variables en c++ y su significado



¿Es posible salir de una antes de tiempo en C++, si se alcanza una condición final? (15)

Quiero saber si es posible finalizar un bucle for en C ++ cuando se verifica una condición final (diferente del número correcto de iteraciones). Por ejemplo:

for (int i = 0; i < maxi; ++i) for (int j = 0; j < maxj; ++j) // But if i == 4 < maxi AND j == 3 < maxj, // then jump out of the two nested loops.

Sé que esto es posible en Perl con la próxima etiqueta o las últimas llamadas LABEL y bloques etiquetados, ¿es posible hacerlo en C ++ o debería usar un ciclo while?

Gracias.


El código de lectura no debe ser como leer un libro de detectives (que siempre debe ser descifrado) ...

un ejemplo:

Java:

iterate_rows: for (int i = 0; i < maxi; ++i) { for (int j = 0; j < maxj; ++j) { if (i == 4 < maxi && j == 3 < maxj) break iterate_rows; else continue iterate_rows; } }

No es necesario que averigüe qué ruptura iterate_rows hace, solo la lee.

C ++:

//iterate_rows: for (int i = 0; i < maxi; ++i) { for (int j = 0; j < maxj; ++j) { if (i == 4 < maxi && j == 3 < maxj) goto break_iterate_rows; else goto continue_iterate_rows; } continue_iterate_rows:; } break_iterate_rows:;

ir a break_iterate_rows es solo una versión visible de break iterate_rows

Si restringe el uso de goto y etiquetas solo en este tipo de código, no estará averiguando la intención. Limitar el uso de goto y etiquetas en este tipo de código hará que simplemente lea el código, no lo analice ni lo descubra. No serás acusado de ser un mal programador.

Y si realmente limita sus conocimientos en este tipo de código, podrá desarrollar el hábito de no tener que descubrir qué hacen esos malditos gotos en su código. El beneficio adicional es que no tienes que introducir booleanos y rastrearlos (lo cual, en realidad, te lleva a detectar el código , lo que hace que sea un poco ilegible, lo que frustra el propósito de evitar los gotos)

PD

Empareje esas etiquetas con comentarios (antes del bucle), para cuando lea más allá de esas líneas con la declaración goto, ya sabe la intención de esos gotos


A pesar de los argumentos "considerados dañinos", este parece ser el lugar perfecto para goto . Eso es esencialmente lo que estás haciendo en Perl. En serio ... considera las alternativas:

Variables adicionales del estado

for (int i=0; i<maxi; ++i) { bool leaveLoop = false; for (int j=0; j<maxj; ++j) { if (i == 4 && j == 3) { leaveLoop = true; break; // leave the inner loop } } if (leaveLoop) { break; // leave the outside loop } }

Salir por excepción

try { for (int i=0; i<maxi; ++i) { for (int j=0; j<maxj; ++j) { if (i == 4 && j == 3) { throw leave_loop(); } } } } catch (leave_loop const&) { }

Lógica compleja

int j = 0; for (int i=0; i<maxi && !(i==4 && j==3); ++i) { for (j=0; j<maxj && !(i==4 && j==3); ++j) { // inner loop } }

goto

for (int i=0; i<maxi; ++i) { for (int j=0; j<maxj; ++j) { if (i==4 && j==3) { goto leave_loop; } } } leave_loop:

¿Está el último menos claro? No creo que sea así. ¿Es más frágil? En mi humilde opinión, los otros son bastante propensos a errores y frágiles en comparación con la versión goto . Perdón por estar de pie en la tribuna aquí, pero esto es algo que me ha molestado por un tiempo;)

Lo único con lo que tienes que estar en contacto es que las excepciones goto y son bastante similares. Ambos abren la oportunidad de perder recursos y lo que no los trata con cuidado.


De todas las sugerencias anteriores, evitaría usar el mecanismo de prueba / captura porque las excepciones deberían reservarse para circunstancias excepcionales y no para el flujo de control normal.

Usar dos descansos está bien si puedes crear la segunda condición apropiadamente. Usar un booleano para este propósito también sería bueno, e incluso podrías conectarlo a la condición de cada ciclo for. Por ejemplo:

bool exit_loops = false; for (int a = 0; a < A && !exit_loops; ++a) { for (int b = 0; b < B && !exit_loops; ++b) { if (some_condition) exit_loops = true; } }

Aunque si está utilizando más de dos bucles, podría ser más apropiado envolverlos en una función y simplemente usar regresar para salir de la función (y todos los bucles también). Por otra parte, podría refactorizar el código de una manera que elimine todos los bucles, sea llamando a una función para ejecutar el código interno del bucle, etc.

Por último, no tengas miedo de usar un goto en esta circunstancia, generalmente los goto son una mala programación desestructurada, pero en algunos casos (como este) son muy útiles.


No puede saltar de dos bucles con una sola instrucción de interrupción, pero podría usar un goto para saltar desde el bucle interno justo afuera.

Si el goto está localizado, y significa que hay menos lógica de lo contrario, creo que es un código perfectamente aceptable. Tener variables de bandera adicionales, o alzar la variable del iterador fuera del bucle interno para que pueda compararlo en el bucle externo no hace que sea más fácil de entender el código en mi humilde opinión.


Otra razón para reconsiderar for completo el constructo es que su alcance impide el acceso a las variables controladas una vez que el ciclo ha finalizado. Los valores de las variables que se mutan en el ciclo pueden ser útiles por una variedad de razones (por ejemplo, para distinguir el éxito del fracaso en una búsqueda) que de otro modo requerirían variables adicionales para preservar esa información después de la salida del alcance. Aquí hay un pequeño ejemplo que busca una matriz cuadrada llamada a para un valor target (suponiendo que SIZE no sea cero, de lo contrario, ¡no es necesaria la búsqueda!):

int i = 0; int j = 0; while (i < SIZE && a[i][j] != target) { // still in array but not at target if (SIZE <= ++j) { // fallen off the end of a row j = 0; ++i; } }

El código subsiguiente puede usar i < SIZE para determinar si se localizó el valor deseado.

Otra ventaja de lo anterior es la flexibilidad. Supongamos que ahora estamos informados de que los valores en las filas de a son ascendentes, por lo que el resto de una fila es irrelevante si se encuentra un valor mayor que el target . Es fácil saber exactamente qué cambio hacer y dónde hacerlo. Debido a que la nueva información nos permite abandonar la fila actual, solo la decisión interna se ve afectada, convirtiéndose en:

if (target < a[i][j] || SIZE <= ++j) { // can''t be in row or fallen off end ...

Veo más idiomas nuevos (especialmente los de orientación funcional) que abandonan la antigua construcción de bucle de "conteo"; eso es probablemente una buena cosa, ya que nos anima a pensar sobre el significado del ciclo, en lugar de simplemente contar.


Permítanme decir esto de manera tan enfática (pero educadamente ;-) como pueda: El for construir en lenguaje c-like no se trata de contar.

La expresión de prueba que determina si continuar puede ser cualquier cosa que sea relevante para el propósito del ciclo; la expresión de actualización no tiene que ser "agregar uno a un contador".

for (int i = 0, j = 0; i < maxi && j < maxj && i != 4 && j != 3;) { if (j < maxj) { ++j; } else { j = 0; ++i; } }

sería una forma (bastante arbitraria) de reescribir.

El punto es que si establecer una condición es el punto de una interacción, por lo general es posible escribir un bucle (usando while o for ) de una manera que indique la condición de continuar / terminar más explícitamente.

(Si pudiera publicar una descripción de lo que está sucediendo realmente, probablemente escriba algo que no parezca tan arbitrario como el anterior).


Podría usar una declaración goto , pero generalmente se considera una mala práctica.

Tu otra opción es hacer algo como esto

int i; int j = 0; for (i = 0; i < maxi && !(i==4 && j==3); ++i) for (j = 0; j < maxj && !(i==4 && j==3); ++j)


Puede usar la palabra clave return : mover el bucle anidado en una subrutina, invocar la subrutina para ejecutar los bucles anidados y ''regresar'' desde la subrutina para salir de [todos] los bucles.


Puedes usar etiquetas, algo como:

Outer: for(...) { Inner: for(...) { if(condition) { goto End; } } } End:

En Java, puede pasar etiquetas para romper, ¿no?

Editar - Cambié el goto a End en lugar de a External, sin embargo, no creo que el representante negativo esté justificado. Esta respuesta da la forma más simple de hacerlo.


Siempre he tratado de mantenerme alejado de las declaraciones de goto (siempre fue menospreciado en la escuela y en mi trabajo por algún motivo). Usaría algo como lo que sugirió Daemin.


Tengo algunas sugerencias:

  1. lanzar .... poner los dos bucles dentro de un "try {}" y luego "atrapar" el "tiro" con la condición.

  2. pon los dos bucles en un método y regresa con la condición.

  3. Goto no es malvado es el uso que las personas le dan también ... Puedes usar "goto" para que pueda ser el código más claro, especialmente cuando se manejan errores. No he usado uno en 20 años.

Tony


La mejor manera que he visto involucra macros y giros, pero en realidad es bastante agradable (el enlace a la publicación comienza hablando de Perl, pero el último párrafo introduce las macros).

Le permite escribir código como:

named (LOOPS) for (i=1; i<10; i++) { for (j=1; j<10; j++) { for (j=1; j<10; j++) { /* Process data[i][j][k] here */ if (data[i][j][k] < threshold) break(LOOPS); } } }


for (int i = 0; i < maxi; ++i) { int j = 0; for (j = 0; j < maxj; ++j) { if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here break; // exit inner loop } if (i == 4 && j == 3) // i < maxi and j < maxj otherwise we would not be here break; // exit outer loop }


bool done = false; for (int i = 0; i < maxi && !done; ++i) for (int j = 0; j < maxj && !done; ++j) if (i == 4 && i < maxi && j == 3 && j < maxj ) done = true; else { }

O podrías simplemente ir a Goto. O no :-)


No puede saltar así en C / C ++:

for (...) { for (...) { // from here... } } // ...to here

sin el uso de goto Necesitas una construcción como:

for (...) { bool exit = false; for (...) { if (do_exit) { exit = true; // or set outer loop counter to end value break; } } if (exit) { break; } }

Alternativamente, use throw and catch, pero eso no es genial, ya que throw debería usarse para excepciones y no para controlar el flujo.

Una forma limpia es hacer que el bucle interno sea una función:

bool F () { if inner loop terminates, return false else return true } void G () { for (...) { if (!F ()) { break; } } }