Подтвердить что ты не робот

Что такое аккуратный способ вырваться из многих за петли сразу?

Предположим, мне нужно вырваться из трех или четырех вложенных циклов сразу при появлении какого-либо события внутри самого внутреннего цикла. Что такое аккуратный способ сделать это?

то, что я делаю, это использовать флаги следующим образом:

int i, j, k;
int flag1 = 0;
int flag2 = 0;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                flag1 = 1;
                flag2 = 1;
                break;
            }
        }
        if (flag1 == 1)break;
    }
    if (flag2 == 1)break;
}

Я не думаю, что это особенно опрятно.

Как бы вы выполнили одно и то же? (без использования переходов)

4b9b3361

Ответ 1

используйте goto. он чист и прост.

Ответ 2

Поместите все петли в функцию и просто верните, а не перерыв.

Ответ 3

Если вы используете Java, вы можете связывать метки с каждым для блока, а затем ссылаться на метку после инструкции continue. Например:

outerfor:
for (int i=0; i<5; i++) {
    innerfor:
    for (int j=0; j<5; j++) {
        if (i == 1 && j == 2) {
             continue outerfor;
        }
    }
}

Ответ 4

Как бы вы выполнили одно и то же? (без использования переходов)

Почему? Ничто не является повсеместно злым, и каждый наложенный инструмент использует его (кроме gets()). Использование goto здесь делает ваш код более чистым и является одним из единственных вариантов, которые мы имеем (предполагая C). Посмотрите:

int i, j, k;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                goto END;
            }
        }
    }
}
END:

Гораздо чище, чем все эти переменные флага, и он даже более четко показывает, что делает ваш код.

Ответ 5

Просто немного лучше.

int i, j, k;
int flag1 = 0;
int flag2 = 0;

for (i = 0; i < 100 && !flag2; i++) {
    for (j = 0; j < 100 && !flag1; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                flag1 = 1;
                flag2 = 1;
                break;
            }
        }
    }
}

Но если вам действительно нужно иметь эти циклы, тогда имеет смысл явно декларировать в каждом цикле, какие условия должны быть выполнены для продолжения, для удобства чтения.

Ответ 6

goto. Это одно из немногих мест, где goto является подходящим инструментом, и обычно это аргумент, представленный, почему goto не является полным злом.

Иногда, однако, я делаю это:

void foo() {
    bar_t *b = make_bar();
    foo_helper(bar);
    free_bar(b);
}

void foo_helper(bar_t *b) {
    int i,j;
    for (i=0; i < imax; i++) {
        for (j=0; j < jmax; j++) {
            if (uhoh(i, j) {
                return;
            }
        }
    }
}

Идея заключается в том, что я получаю гарантированный бесплатный балл, плюс я получаю чистый двухуровневый выход из коммутатора через возврат.

Ответ 7

Если вы абсолютно не хотите использовать goto, установите для всех условий цикла значение false:

int i, j, k;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                i = j = k = INT_MAX;
                break;
            }
        }
    }
}

Примечание: интеллектуальный оптимизирующий компилятор превратит содержимое if в прыжке в конец самого внешнего цикла

Ответ 8

иногда вы можете использовать трюк следующим образом:

for (i = 0; i < 100 && !flag2; i++) {
for (j = 0; j < 100 && !flag1; j++) {
    for (k = 0; k < 100; k++) {
        if (k == 50) {
            k = 100;
            i = 100;
            j = 100;
        }
    }
}

}

или объявить флаг добавления в вашем цикле:

bool end = false;
for(int i =0; i < 1000 && !end; i++) {
   //do thing
   end = true;
}

это стоит только строка, но чистая, я думаю.

джастин

Ответ 9

Если преждевременное завершение любого цикла всегда означает, что вы также должны разбить замкнутый цикл, тогда вам не нужны дополнительные флаги. Все это может выглядеть следующим образом

int i, j, k;
for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50)
                break;
        }
        if (k < 100) break;
    }
    if (j < 100) break;
}

По моему опыту, это то, что необходимо в большинстве случаев.

Ответ 10

немного глупо самодокументирующегося:

int i, j, k;
int done = 0;

for (i = 0; i < 100 && ! done; i++) {
    for (j = 0; j < 100 && ! done; j++) {
        for (k = 0; k < 100 && ! done; k++) {
            if (k == 50) we_are(done);
        }
    }
}

//...

void we_are(int *done) {
    *done = 1;
}

но на самом деле у вас не должно быть трех вложенных циклов. Вы должны рассмотреть возможность реорганизации в разные функции и улучшить свою программную логику вместо этого.

Хотя я согласен, что иногда goto действительно лучшее решение, я думаю, что любая проблема, к которой goto является решением, является результатом плохого кода.

Ответ 11

Разделение на 0 - самый верный метод, который я знаю, который нарушит вас из любого числа циклов. Это работает, потому что команда сборки DIV не любит такую ​​глупость.

Итак, вы можете попробовать следующее:

int i, j, k;
int flag1 = 0;
int flag2 = 0;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                flag1 = 1;
                flag2 = 1;
                int z = 1 / 0;  // we're outta here!!!
            }
        }
        if (flag1 == 1)break;
    }
    if (flag2 == 1)break;
}

Возвращение из trap, которое происходит на таких событиях, оставлено как упражнение для читателя (это тривиально).

Ответ 12

Я бы сделал что-то вроде:

  int i, j, k;

  for (i = 0; i < 100; i++) {
      for (j = 0; j < 100; j++) {
          for (k = 0; k < 100; k++) {
              if (k == 50) {
                  return;
              }
          }
      }
  }

Ответ 13

Если вы используете GCC и эту библиотеку, break может принять количество вложенных циклов, которые вы хотите закрыть:

int i, j, k;

for (i = 0; i < 100; i++) {
    for (j = 0; j < 100; j++) {
        for (k = 0; k < 100; k++) {
            if (k == 50) {
                break(3);
            }
        }
    }
}

Ответ 14

Один из способов сделать это - конечный автомат. Но я все равно буду использовать goto. Это намного проще.:)

state = 0;
while( state >= 0){
    switch(state){
        case 0: i = 0; state = 1; // for i = 0
        case 1:
            i++; 
            if (i < 100)   // if for i < 100 not finished
                state = 2; // do the inner j loop
            else
                state = -1; // finish loop
        case 2: j = 0; state = 3; // for j = 0
        case 3: 
            j++;
            if (j < 100)  // if j < 100 not finished
                state = 4 // do the inner k loop
            else
                state = 1; // go backt to loop i
            break;
        case 4: k = 0; state = 5;
        case 5:
            k++;
            if (k == 50){
                state = -1;
                break;
            }
            if (k < 100) // if k loop not finished
                state = 5; // do this loop
            else
                state = 3; // go back to upper loop
            break;
        default : state = -1;
    }
}