2016-10-14 4 views
0

Работает на моей базе сертификации .net. На практическом тесте возникает вопрос с некоторым примером кода, запрашивающим вывод. Правильный ответ ... Loop 3 Loop 2 Loop 1 Loop 1Простой while цикл повторяет последнее значение

проблема, я не понимаю, почему это повторять, что последний "Loop 1". Я положил его в VS2015 и обнаружил, что он на самом деле правильный. Обратите внимание: я не прошу, чтобы код был исправлен, я прошу объяснить, почему он повторяет последнее значение. Я искал и не нашел четкого ответа. Итак, вот код.

namespace ConsoleApplication5 
{ 
class Program 
{ 
    private static int WriteToConsole(int NumWrites) 
    { 
     int i = NumWrites; 
     while (i > 0) 
     { 
      Console.WriteLine("loop {0}", i); 
      i = WriteToConsole(i - 1); 
     } 
     return NumWrites - 1; 
    } 

    static void Main(string[] args) 
    { 
     WriteToConsole(3); 
     Console.ReadKey(); 
    } 
} 
} 
+4

Лучший способ понять это - установить точку останова в 'WriteToConsole (3);' в 'Main()' и отлаживать ее шаг за шагом. –

ответ

8

Изучите раскручивание штабеля.

Я попытаюсь дать вам представление.

Заказ вызова будет WriteToConsole (3), затем WriteToConsole (2), затем WriteToConsole (1), затем WriteToConsole (0).

WriteToConsole (0) вернет -1 в WriteToConsole (1), поэтому он снова не включится во время цикла.

WriteToConsole (1) вернет 0 в WriteToConsole (2), поэтому он не будет снова включен в цикл.

WriteToConsole (2) вернет 1 в WriteToConsole (3), чтобы он соответствовал условию (i> 0) и записывал на консоль.

+0

Спасибо, Вивек. Заметка об изучении раскручивания стека была еще более полезной, чем объяснение этой конкретной проблемы. Это именно то, что мне нужно. –

0

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

Чем выше начальное значение тем больше повторений вы найдете в результате

0

Это связано с тем, как рекурсивный метод лечения i. Каждый раз, когда вызывается WriteToConsole, он возвращает нубмер, который он вычитал на 1. Но когда он вызывается внутри цикла while, он вызывается с i - 1, поэтому по сути этот метод выполняет i = i - 2;. При каждом из номеров выполняются с этой моделью, вы получите следующее поведение:

  • WriteToConsole(3); выполняет дважды: один раз для 3 и один раз для 1.
  • WriteToConsole(2); выполняет один раз за 2, но не для 0.
  • WriteToConsole(1); выполняет один раз за 1, но не для -1.
  • WriteToConsole(3); только выполняет для 1 после возвращения вложенных рекурсий.

Который производит следующий результат:

loop 3 
loop 2 
loop 1 
loop 1 
1

Вот один из примеров потока кода. Каждый отступ представляет новый стек (рекурсивный вызов WriteToConsole), а переменные i заменяют его текущим значением на этом этапе кода.

WriteToConsole(3) 
    while(3>0) 
    Console.WriteLine(3) 
    WriteToConsole(2) 
     while(2>0) 
     Console.WriteLine(2) 
     WriteToConsole(1) 
      while(1>0) 
      Console.WriteLine(1) 
      WriteToConsole(0) 
       while(0>0) 
       return -1 
      while(-1>0) 
      return 0 
     while(0>0) 
     return 1 
    while(1>0) 
    Console.WriteLine(1) 
    WriteToConsole(0) 
     while(0>0) 
     return -1 
    while(-1>0) 
    return 2 

В recurisive звонки в WriteToConsole основном написать текущий номер, а затем декрементах. Это приведет к написанию от 3 до 1. Но вы можете видеть, что после первого набора рекурсивных вызовов локальная переменная i будет установлена ​​в 1, и у вас будет еще один проход через цикл и, таким образом, он будет печатать 1 a второй раз. Поэтому по этой причине, давая ему начальный номер 4, вы получите выход 4, 3, 2, 1, 1, 2, 1. И переход через 5 даст 5, 4, 3, 2, 1, 1, 2 , 1, 3, 2, 1, 1

Смежные вопросы