Вложенные циклы for с различными вызовами функций - PullRequest
0 голосов
/ 10 июня 2018

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

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

    private static Dictionary<int, string> myDictionary = new Dictionary<int, string>();
    private static int value = 0;

    static void Main(string[] args)
    {
        try
        {
            for (int i = 0; i < 10; ++i)
            {
                if (i == 0)
                {
                    Test0(); //Test0 = 12
                    Console.WriteLine("Test0 = " + i.ToString()); 
                }


                else if (i == 1)
                {
                    Test1(i);
                    Console.WriteLine("Test1 = " + i.ToString());           
                }
                else if (i == 2 && i % 2 == 0) 
                {
                    Test2(ref i); //i=2
                    Console.WriteLine("Test2 = " + i.ToString());
                }

                else if (i == 2)
                {
                    Test1(i); //i=3
                    Console.WriteLine("Test1 = " + i.ToString());                     
                }

                else if (i == 3)
                {
                    Test3(ref i);
                }

                else if (i == 4)
                {
                    string str;
                    str = Test4(i);
                    Console.WriteLine("Test4 = " + (int.Parse(str) + i));                        
                }

                else if (i == 5)
                {
                    Test5(i);
                    Test5(i - 2);
                }

                else if (i == 6)
                {
                    Test6(ref i);
                    Console.WriteLine("Added item to dictionary.");
                }

                else if (myDictionary[i] == "six")
                {
                    Console.WriteLine("Item 6 is in the dictionary.");
                }
                else
                {
                    Console.WriteLine("Entered else clause");
                    int zero = 0;
                    int result = i / zero;
                    Console.WriteLine("Result is " + result.ToString());
                }
            }
            Console.WriteLine("End of loop reached");

        }
        catch
        {
            Console.WriteLine("Catch clause entered");
        }

        finally
        {
            Console.WriteLine("Finally clause entered");
        }

        Console.WriteLine("Finished");

        Console.ReadKey();
    }
    private static void Test0()
    {
        int result = 0;
        for (int i = 1; i <= 3; i++)
        {
            for (int j = 1; j <= 2; j++)
            {
                result += i;
            }
        }
        Console.WriteLine("Test0 = " + result.ToString());
    }
    private static void Test1(int i)
    {
        i = 3;
    }
    private static void Test2(ref int i)
    {
        i = 2;
    }
    private static void Test3(ref int i)
    {
        i = Convert.ToInt32(i + "1") % 9;
    }
    private static string Test4(int i)
    {
        string str;
        str = i.ToString() + i.ToString();
        return str;
    }
    private static void Test5(int i)
    {
        Program.value -= i; //value = 0
        Console.WriteLine("Test5 = " + Program.value.ToString());
    }
    private static void Test6(ref int i)
    {
        myDictionary.Add(i, "six");
        Console.WriteLine("Test6 = " + myDictionary[i]);

    }


}

Ответ Iесли бы это было:

Test0 = 12
Test0 = 0
Test1 = 3
Test2 = 2
Test1 = 3
Test5 = -5
Test5 = -3
Test6 = six
Added item to dictionary
End of loop reached
Catch clause entered
Finally clause entered
Finished

Что явно не так.Правильный ответ:

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.
Catch clause entered
Finally clause entered
Finished

Кто-нибудь чувствует себя как вызов ...?Объяснение будет высоко ценится.Это длинный код ... Приблизительное время, отведенное на этот вопрос на экзамене, составляло около 15 - 20 минут.

Спасибо

1 Ответ

0 голосов
/ 11 июня 2018

Ниже приведен след, где я = 0,1,2,3,4,5,6,7 (сбой)

Когда i = 0

код вызывает метод Test0().Этот метод просто перебирает некоторые «локальные» переменные и выводит результат.«Test0 = 12» Примечание: переменная i является «локальной» и не является той же переменной i, используемой в главном for счетчике цикла.

if (i == 0) {
  Test0(); //Test0 = 12
  Console.WriteLine("Test0 = " + i.ToString());
} else...   

private static void Test0() {
  int result = 0;
  for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 2; j++) {
      result += i;
    }
  }
  Console.WriteLine("Test0 = " + result.ToString());
}

Как только код возвращается из Test0()… Вывод…

Test0 = 12

Примечание: переменная «local» i из Test0 вышла из области видимости, а переменная счетчика i в цикле for выведена…

Test0 = 12
Test0 = 0

Когда i = 1

Код продолжается ... возвращается к циклу for с шагом i = 1.Вводит код ...

if (i == 1) {
  Test1(i);
  Console.WriteLine("Test1 = " + i.ToString());
} else...

private static void Test1(int i) {
  i = 3;
}

Когда i = 1 код вызывает метод Test1(i).Этот метод принимает переменную int в качестве параметра.Когда код входит в метод Test1(int i) ... создается новая переменная LOCAL i.Начальное значение i равно 1, которое было передано. Код просто устанавливает переменную «local» i в значение Three (3), а затем возвращает.

Как только код возвращается из Test1(i) * i переменная, созданная в методе, больше не находится в области видимости, и следующая строка кода выведет переменную i, используемую в счетчике цикла for, которая по-прежнему равна единице (1).Вывод…

Test0 = 12
Test0 = 0
Test1 = 1

Когда i = 2

Код продолжается ... возвращается к циклу for с шагом i = 2.Вводит код ...

if (i == 2 && i % 2 == 0) {
  Test2(ref i); //i=2
  Console.WriteLine("Test2 = " + i.ToString());
} else...

private static void Test2(ref int i) {
  i = 2;
}

Примечание ниже.Здесь переменная передается как ref (ссылка).В настоящее время переменная for counter i равна 2. Когда код входит в метод Test2(ref int i), он НЕ создает свою собственную «локальную» копию.Переменная счетчика i, используемая в основной программе, «подвержена» этому методу, и она «может» ее изменить… как код обязательно делает со следующей строкой кода: i = 2; К счастью, текущее значение i IS уже 2. Изменение i таким способом крайне не рекомендуется, и я бы посчитал, что в лучшем случае это может быть рискованно, в худшем случае - сбой.

Продолжение… i по-прежнему 2 после возврата из Test2(ref i) Вывод…

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2

Когда i = 3

Код продолжается… Возвращается обратно к циклу for с шагом i = 3.Вводит код…

if (i == 3) {
  Test3(ref i);
} else...

private static void Test3(ref int i) {
  i = Convert.ToInt32(i + "1") % 9;
}

Когда i = 3 код вызывает метод Test3(ref i).Здесь, похоже, этот метод пытается «изменить» переменную счетчика i в основном цикле.Чтобы разбить его, когда мы знаем, i = 3

i = Convert.ToInt32(i + "1") % 9;

Становится

i = Convert.ToInt32(“31”) % 9;

Это вернет четыре (4), поскольку 31 мод 9 = 4. Это значение основнойfor переменная счетчика циклов i установлена ​​в.Это означает, что код будет пропущен, когда i=4, поскольку здесь устанавливается значение 4 ... когда код возвращается к циклу for ... он собирается установить i в 5. Кроме того, НЕТ выводакогда i = 3… чтобы подвести итог, поскольку не было нового вывода… Это то же самое, что и предыдущая итерация цикла.

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2

Когда i = 5

Код продолжается ... возвращается к циклу for, помните, что предыдущий вызов Test3(ref i) изменился i до четырех (4), следовательно, конструкция if увеличивает i до i = 5.Вводит код ...

if (i == 5) {
  Test5(i);
  Test5(i - 2);
} else...


private static void Test5(int i) {
  Program.value -= i; //value = 0
  Console.WriteLine("Test5 = " + Program.value.ToString());
}

Когда i = 5 код вызывает метод Test5(i) дважды.Метод Test5(int i) принимает один int параметр i, затем вычитает значение i из глобальной переменной value.На этом этапе мы «знаем» value=0, поэтому value устанавливается в -5.Затем выводит value… Output…

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5

Test5(i); и возвращается второй вызов с Test5(i - 2);

Для отслеживания, i = 5 AND value = -5…поэтому вышеуказанный вызов с использованием i-2 может быть переписан как…

Test5(3);

Здесь внутри Test5, i = 3, код вычитает 3 из value value = -8, затем выводит…

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8

Когда i = 6

Код продолжается ... снова возвращается к циклу for, увеличивается i до i = 6.Вводитметод code…

if (i == 6) {
  Test6(ref i);
  Console.WriteLine("Added item to dictionary.");
} else...

private static void Test6(ref int i) {
  myDictionary.Add(i, "six");
  Console.WriteLine("Test6 = " + myDictionary[i]);
}

Test6(ref int i) добавляет значение в глобальный словарь myDictionary и выводит его из словаря.Выход….

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six

Как только код возвращается из Test6(ref int i), выводится строка…

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.

Когда i = 7

Кодпродолжается… возвращается к циклу for, увеличивается с i до i = 7.Вводит код…

if (myDictionary[i] == "six") {
  Console.WriteLine("Item 6 is in the dictionary.");
}
else {
  Console.WriteLine("Entered else clause");
  int zero = 0;
  int result = i / zero;
  Console.WriteLine("Result is " + result.ToString());
}

Приведенный ниже код вызывает исключение.

myDictionary[i] == "six"

Так как i = 7, myDictionary[i] собирается выйти из строя и выдает «ключ», которого нетв словарном исключении, и это имеет смысл, так как мы знаем, что в словаре есть только один элемент, и он равен 6. Поэтому исключение перехватывается, и дисплей обновляется…

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.
Catch clause entered

Предложение finallyоператора try выполняется….

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.
Catch clause entered
Finally clause entered

Наконец, выводится последняя строка и код завершается.Выходные данные…

Test0 = 12
Test0 = 0
Test1 = 1
Test2 = 2
Test5 = -5
Test5 = -8
Test6 = six
Added item to dictionary.
Catch clause entered
Finally clause entered
Finished

Ниже составное условие if (и последующее) не имеет большого смысла.Если i НЕ равно двум (2), тогда (из-за короткого замыкания) вторая часть условия «и» никогда не будет оцениваться.Следовательно, i % 2 == 0 будет оцениваться только тогда, когда i=2 ???Я уверен, что по модулю (2,2) всегда будет возвращаться 0. Суть в том, что второе условие никогда не оценивается, если только i = 2, которое всегда будет истинным, поэтому этот if можно переписать как if (i == 2).Вот почему «второй» оператор if (i == 2) в части «else» этого оператора if (i == 2) НИКОГДА не будет выполнен.

else if (i == 2 && i % 2 == 0) {
  Test2(ref i); //i=2
  Console.WriteLine("Test2 = " + i.ToString());
}
else if (i == 2)
  {… never get here….

Чтобы помочь, я рекомендую вам взглянуть поближе на «красный флаг»В коде.Передача по ref не является большой проблемой, однако передача «индекса» цикла по ref и изменение его значения - это огромный красный флаг.Отслеживание кода стало более сложным.Это то, что вам нужно полностью понять, следовательно, тест.Тест выполняет что-то (изменение индекса цикла), что вы редко видели бы в любой среде.Поэтому при отслеживании кода, который делает это, требуется особая осторожность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...