具有不同函数调用的嵌套for循环

时间:2018-06-10 10:14:37

标签: c# for-loop

我目前正在修改决赛。做一些考试准备并遇到过这个特别过去的问题,我发现很难掌握。

问题要求写下以下代码的输出:

    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]);

    }


}

我的答案是:

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 :(得分:0)

以下是i = 0,1,2,3,4,5,6,7(崩溃)

的痕迹
  

i = 0

代码调用Test0()方法。这种方法只是循环一些“局部”变量并输出结果。 “Test0 = 12”注意:i变量是“local”,并且与主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

注意:来自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变量设置为三(3)然后返回。

代码从Test1(i)返回后,方法中创建的i变量不再在范围内,下一行代码将输出i变量,该变量在{ {1}}循环计数器,仍然是一(1)。输出...

for
  

当i = 2时

代码继续......分支回Test0 = 12 Test0 = 0 Test1 = 1 循环,递增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为2.当代码进入i方法时,它不会创建自己的“本地”副本。主程序中使用的计数器变量Test2(ref int i)被“暴露”给这个方法并且它“可以”改变它......因为代码必须对下一行代码进行处理:i这是幸运的当前值i = 2;已经是2.以这种方式改变i是非常气馁的,我认为最坏的情况是崩溃风险。

i输出...

返回后,继续... i仍为2
Test2(ref i)
  

当i = 3时

代码继续......分支回Test0 = 12 Test0 = 0 Test1 = 1 Test2 = 2 循环,递增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;

这将返回四(4),因为31 mod 9 = 4.这是主i = Convert.ToInt32(“31”) % 9; 循环计数器变量for设置为的值。这意味着代码将在i时跳过,因为它在此处设置为4 ...当代码分支回到i=4循环时......它将for设置为5。另外,当i ...总结时没有输出,因为没有新的输出......它与循环的前一次迭代相同。

i = 3
  

当i = 5时

代码继续...分支回到Test0 = 12 Test0 = 0 Test1 = 1 Test2 = 2 循环,记住上一次调用for已将Test3(ref i)更改为四(4),因此i构造增量ifi。输入代码......

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设置为-5。然后输出value ...输出...

value

Test0 = 12 Test0 = 0 Test1 = 1 Test2 = 2 Test5 = -5 返回,并使用Test5(i); ...

进行第二次通话

要跟踪,Test5(i - 2);i = 5 ...因此,使用value = -5进行上述调用可以重写为...

i-2

在Test5中,Test5(3); = 3,代码从i value中减去3,然后输出...

value = -8
  

当i = 6时

代码继续...分支回到Test0 = 12 Test0 = 0 Test1 = 1 Test2 = 2 Test5 = -5 Test5 = -8 循环,将for增加到i。输入代码......

i = 6

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)
  

当i = 7时

代码继续...分支回到Test0 = 12 Test0 = 0 Test1 = 1 Test2 = 2 Test5 = -5 Test5 = -8 Test6 = six Added item to dictionary. 循环,将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将失败并抛出字典异常中不存在的“密钥”,这是有道理的,因为我们知道字典中只有一个项目,它是6因此,异常被捕获并且显示更新......

myDictionary[i]

执行try语句的Test0 = 12 Test0 = 0 Test1 = 1 Test2 = 2 Test5 = -5 Test5 = -8 Test6 = six Added item to dictionary. Catch clause entered 子句......。

finally

最后输出最后一行并退出代码。输出...

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不等于二(2)那么(由于短路),“和”条件的第二部分将永远不会被评估。因此,评估的唯一时间ii % 2 == 0 ???我确信modulo(2,2)将始终返回0.这里的重点是第二个条件永远不会被评估,除非i=2始终为真,因此i = 2可以重写为{{1} }}。这就是为什么这个if语句的“else”部分中的“第二个”if (i == 2)语句永远不会被执行。

if (i == 2)

为了提供帮助,我建议您仔细查看代码中的“红旗”。通过ref传递不是一个大问题,然而,通过ref传递一个循环的“索引”并改变它的值是一个巨大的红旗挥舞着。跟踪代码变得更加复杂。这是你需要完全理解的测试。测试正在做一些你很少在任何环境中看到的东西(改变循环索引)。因此,在跟踪执行此操作的代码时需要格外小心。