попасть в цикл, когда начальное условие ложно - PullRequest
0 голосов
/ 06 октября 2011

Я запутался и понятия не имею, что здесь происходит:

#include <iostream>

void recur();
int i = 1;

int main() {
  recur();
}

void recur() {
  std::cout << "\nvalue of i above while loop : " << i << std::endl;
  while(i++ < 10) {
    recur();
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
  }
}

Вот вывод:

value of i above while loop : 1

value of i above while loop : 2

value of i above while loop : 3

value of i above while loop : 4

value of i above while loop : 5

value of i above while loop : 6

value of i above while loop : 7

value of i above while loop : 8

value of i above while loop : 9

value of i above while loop : 10
statement just after the recursive call to tester and here the value of i is :11
statement just after the recursive call to tester and here the value of i is :12
statement just after the recursive call to tester and here the value of i is :13
statement just after the recursive call to tester and here the value of i is :14
statement just after the recursive call to tester and here the value of i is :15
statement just after the recursive call to tester and here the value of i is :16
statement just after the recursive call to tester and here the value of i is :17
statement just after the recursive call to tester and here the value of i is :18
statement just after the recursive call to tester and here the value of i is :19

Каждый раз, когда вызывается функция recurпечатает свою первую строку, и когда значение становится равным 10, цикл прерывается. Теперь, когда мы находимся вне цикла, как работает / печатает оператор в цикле while?Может кто-нибудь объяснить, что происходит?

Позвольте мне проверить Правильно ли я думаю?При каждом вызове функции recur управление возвращается к началу определения функции.Например:

while(i++<10) { 
   recur();
   //...
}
  |
  |
 \ /
void recur() { // here i is 2
    while(i++ < 10) {
        recur();
        //....
    }
} 
  |
  |
 \ /
void recur() { // here i is 3
    while(i++ < 10) {
        recur();
        //....
    }
} 

Так идут звонки?

Ответы [ 6 ]

3 голосов
/ 06 октября 2011

Переменная i продолжает увеличиваться, потому что условное выражение while должно быть выполнено еще раз, чтобы убедиться, что оно ложно, в результате чего i увеличивается, даже если оно превышает 10 для каждого вызова recur ().

Если вы поместите увеличение i за пределы условного, результаты будут в большей степени соответствовать ожидаемому.Например:

while (i < 10) {
    i++;
    // Do rest.
}

Но с вашим текущим кодом, каждый раз, когда проверяется условное выражение, i продолжает увеличиваться, даже если условное условие ложно.

2 голосов
/ 06 октября 2011

Вы смешиваете рекурсию и итерацию довольно странным образом.

Первый recur () вызывает второй, который вызывает третий и так далее. Каждое увеличение i. Когда десятый вложенный вызов функции увеличивает i до 10, он возвращается. Затем вызов 9-й функции печатает сообщение, увеличивает его еще раз, выходит из цикла и возвращается к 8-му, что делает то же самое.

Ни одна из функций не обходит цикл while более одного раза - потому что когда возвращается вложенный вызов recur (), i всегда равен по крайней мере 10.

Зачем ты это делаешь?

1 голос
/ 06 октября 2011

Вот поток вашей программы:

value   function    stack depth
-----   --------    -----------
i = 1   recur()     0
i = 1   print i     1
i = 1   i++         1
i = 2   recur()     1
i = 2   print i     2
i = 2   i++         2
i = 3   recur()     2
i = 3   print i     3
i = 3   i++         3
i = 4   recur()     3
i = 4   print i     4
i = 4   i++         4
i = 5   recur()     4
i = 5   print i     5
i = 5   i++         5
i = 6   recur()     5
i = 6   print i     6
i = 6   i++         6
i = 7   recur()     6
i = 7   print i     7
i = 7   i++         7
i = 8   recur()     7
i = 8   print i     8
i = 8   i++         8
i = 9   recur()     8
i = 9   print i     9
i = 9   i++         9
i = 10  recur()     9
i = 10  print i     10
i = 10  i++         10
i = 11  return      10
i = 11  print i     9
i = 11  i++         9
i = 12  return      9
i = 12  print i     8
i = 12  i++         8
i = 13  return      8
i = 13  print i     7
i = 13  i++         7
i = 14  return      7
i = 14  print i     6
i = 14  i++         6
i = 15  return      6
i = 15  print i     5
i = 15  i++         5
i = 16  return      5
i = 16  print i     4
i = 16  i++         4
i = 17  return      4
i = 17  print i     3
i = 17  i++         3
i = 18  return      3
i = 18  print i     2
i = 18  i++         2
i = 19  return      2
i = 19  print i     1
i = 19  i++         1
i = 20  return      1
i = 20
1 голос
/ 06 октября 2011

Нет, когда recur() возвращается, вы все еще в операторе while, вам нужно выполнить std::cout после recur().

void recur() {
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    while(i++ < 10) {
        recur();
        // <b>each time `recur()` returns, its return to here</b>
        std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
      }
}

хорошо, я рисую график

while(i++<10) { 
    recur();
    //...       <---------return to here--
}                                        |
                                         |
void recur() { // here i is 2            |
    while(i++ < 10) {                    |
        recur();                         |
        //....  <-----return to here---- |
    }                                  | |
    return; ------------------------------
}                                      |
                                       |
void recur() { // here i is 3          |
    while(i++ < 10) {                  |
        recur();                       |
        //....                         |
    }                                  |
    return; ----------------------------
} 
0 голосов
/ 06 октября 2011

Я думаю, что лучший способ объяснить это - показать, как я бы переписал функцию, чтобы она была более читабельной. Каждый из следующих фрагментов будет иметь вывод, идентичный исходному коду (при условии, что i == 1 при первом вызове recur ())

Во-первых, давайте возьмем оператор постинкремента из условия, потому что я думаю, что это сбивает с толку. Этот код эквивалентен:

void recur() {
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    while(i < 10){
        i++;
        recur();
        std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;

    }
    i++;
}

Обратите внимание, как в конце находится i ++. Это связано с тем, что в исходном коде я буду увеличивать себя в условии (i ++ <10), даже если условие не оценивается как true и не входит в цикл. </p>

Далее, вы можете сортировать повторяемость, многократно вставляя код. Я также отслеживаю значение i каждый раз, когда его значение изменяется.

void recur() {
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    while(i < 10){
        i++; //i == 2
        std::cout << "\nvalue of i above while loop : " << i << std::endl;
        while(i < 10){
            i++; //i == 3
            std::cout << "\nvalue of i above while loop : " << i << std::endl;
            while(i < 10){
                i++; //i ==4
                std::cout << "\nvalue of i above while loop : " << i << std::endl;
                while(i < 10){
                    i++; //i == 5
                    std::cout << "\nvalue of i above while loop : " << i << std::endl;
                    while(i < 10){
                        i++; //i == 6
                        std::cout << "\nvalue of i above while loop : " << i << std::endl;
                        while(i < 10){
                            i++; //i == 7
                            std::cout << "\nvalue of i above while loop : " << i << std::endl;
                            while(i < 10){
                                i++; //i == 8
                                std::cout << "\nvalue of i above while loop : " << i << std::endl;
                                while(i < 10){
                                    i++; //i == 9
                                    std::cout << "\nvalue of i above while loop : " << i << std::endl;
                                    while(i < 10){
                                        i++; //i == 10
                                        std::cout << "\nvalue of i above while loop : " << i << std::endl;
                                        while(i < 10){//this doesn't evaluate to true since i == 10
                                            //we stop unrolling here because the interior of this loop won't be executed anyway
                                        }
                                        i++; // i == 11
                                        std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
                                    }
                                    i++;
                                    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
                                }
                                i++;
                                std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
                            }
                            i++;
                            std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
                        }
                        i++;
                        std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
                    }
                    i++;
                    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
                }
                i++;
                std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
            }
            i++;
            std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
        }
        i++;
        std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    }
    i++;
}

Обратите внимание, что каждый цикл while выполняется только один раз - к тому времени, когда первый цикл while завершается в первый раз, i больше десяти, поэтому цикл не будет введен во второй раз. Имея это в виду, мы можем полностью избавиться от времен и сохранить некоторые отступы.

void recur() {
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i == 2
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i == 3
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i ==4
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i == 5
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i == 6
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i == 7
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i == 8
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i == 9
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //i == 10
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; // i == 11
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
    std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    i++;
}

Можно также оптимизировать некоторые из этих повторяющихся утверждений ...

void recur(){
    for(int x = 0; x < 10; x++){
        std::cout << "\nvalue of i above while loop : " << i << std::endl;
        i++;
    }
    for(int x = 0; x < 9; x++){
        std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
        i++;
    }
}

Теперь совершенно очевидно, что первое утверждение печатается само для i = 1 до 10, а второе от i = 11 до 19.

0 голосов
/ 06 октября 2011

После того, как условие становится ложным в самом внутреннем вызове recur, оно выходит из цикла и возвращается правильно.Он возвращается ко второму внутреннему вызову recur, который отображает значение i, а затем возвращается к началу цикла while, чтобы снова проверить условие.Условие равно (i++ < 10), поэтому оно увеличивается i во второй раз (теперь до одиннадцати), видит, что оно больше десяти, и возвращается к третьему внутреннему вызову.Третье самое внутреннее приращение проверяет (i++ < 10), требуя, чтобы оно увеличивало i (до двенадцати), прежде чем оно узнает о выходе из цикла , это .и т.д.

По сути, у вас есть один цикл на вызов.Это только из одного за раз.Вы хотите:

void recur() {
    std::cout << "\nvalue of i above while loop : " << i << std::endl;
    i++; //here, outside the loop
    while(i < 10) {
        recur();
        std::cout << "statement just after the recursive call to tester and here the value of i is :" << i << std::endl;
    }
}

[РЕДАКТИРОВАТЬ]
Да, когда функция вызывает себя, компьютер снова вызывает эту функцию, а когда внутренняя функция возвращается, она возвращается именно туда, где былавнешняя функция.По сути, как и любой другой вызов функции, работает.

...