有趣的面试练习结果:return、post increment 和 ref 行为 [重复]

Posted

技术标签:

【中文标题】有趣的面试练习结果:return、post increment 和 ref 行为 [重复]【英文标题】:Interesting interview exercise result: return, post increment and ref behavior [duplicate] 【发布时间】:2017-09-18 06:42:50 【问题描述】:

这是一个简单的控制台应用程序代码,它返回的结果我完全看不懂。

试想一下它在控制台输出的是0、1还是2:

using System;

namespace ConsoleApplication

    class Program
    
        static void Main()
        
            int i = 0;
            i += Increment(ref i);

            Console.WriteLine(i);
            Console.ReadLine();
        

        static private int Increment(ref int i)
        
            return i++;
        
    

答案是 0。

我不明白为什么在Increment 方法上执行i++ 后增量i++,该方法在ref 上执行(而不是在传递的变量的副本上)确实增加了变量,但它只是稍后会被忽略。

我的意思是在这个视频中:

有人能解释一下这个例子吗?为什么在调试过程中我看到值递增到 1,然后又回到 0?

【问题讨论】:

在执行return i++ 时,i 的值(即 0)在递增之前返回。虽然可能会发生增量,但该值被丢弃,因为它已经返回。尝试改用return ++i; 虽然这是一个答案谜题,但它是一个非常愚蠢的面试问题,IMO。它应该被标记为“语言律师”,因为这种行为取决于一个非常小众的语言规则,你希望永远不会在行动中遵守,因为(希望)你在实践中永远不会看到这样的代码 @Alexander 同意了。如果为我工作的人写了这样的代码,我会坐下来和他们“交谈” 一些相关的问题,也提供了一些关于幕后发生的事情的好信息:***.com/questions/33783989/… 如果我在面试中得到了这段代码,我的第一个答案是:“我可以为这段代码编写测试(如果它们不存在的话),然后将它重构为理智吗?” 【参考方案1】:

i += Increment(ref i); 等价于

i = i + Increment(ref i);

赋值右边的表达式是从左到右求值的,所以下一步是

i = 0 + Increment(ref i);

return i++返回i的当前值(即0),然后递增i

i = 0 + 0;

在赋值之前,i 的值是 1(在 Increment 方法中递增),但赋值又使它变为 0。

【讨论】:

...你比我快一点;) 谢谢你,Jakub,详细信息,现在为什么它是 1 又变成 0 是有道理的。 免责声明:我有 C++ 背景,对 C# 知之甚少。但我对此感到困惑。所以显然 C# 定义强制编译器,在像i+=f(); 这样的语句中,开始制作i 值的本地匿名副本,然后调用f,它可以(如果它可以访问)愚弄变量i 它想要的一切,知道留在该变量中的值无论如何都会被遗忘,因为它将被i 之前制作的匿名副本和f 返回的值之和覆盖。非常好奇。似乎与使+= 简单快速的想法背道而驰。 不,我想它会很好定义。虽然 C++ 标准基本上(并且懒惰地)将var+=expr 定义为等同于var=var+expr,但它确实有两个例外:左值var 仅评估一次,并且“对于不确定顺序的函数调用,操作复合分配是一个单一的评估”。这并不完全清楚,但它似乎确实禁止在函数调用之前使用var 的提取和函数调用之后的var 的存储来实现该操作。如果您关心,请参阅***.com/q/24194076/1436796。 @MarcvanLeeuwen 如果评估顺序被定义为严格从左到右是有意义的。鉴于var = var + expr 和从左到右的评估,var 将始终在评估expr 之前检查,因此exprvar 所做的任何更改都不会反映在其中。我猜 C# 只是为它定义了比 C++ 更严格的排序。【参考方案2】:

我认为这里的“魔法”只是操作优先级操作的顺序

i += Increment(ref i)

一样
i = i + Increment(ref i)

+操作从左到右执行

所以首先我们取 i ... 当时是 0 ...

然后我们添加 Increment(ref i) 的结果 ... 这也是 0 ... 0+0=0 ... 但是等待 ... 在我们得到结果之前 i 实际上是递增的 ...

该增量发生在我们的 + 操作的左操作数被评估之后......所以它不会改变任何东西...... 0+0 仍然是 0......因此在 + 操作之后 i 被分配为 0被处决

【讨论】:

与优先级无关,与从左到右的评估有关。 仔细阅读...运算符优先级!=操作优先级...导致从左到右的顺序... 我仔细阅读了。你写的不好。使用正确的术语 - 操作顺序,而不是优先级。优先级决定了 AST 如何从其他不明确的输入中构建。操作/评估的顺序决定了如何将 AST 评估为结果。使用短语“操作优先级”意味着两者都不是。 嗯...谢谢你的英语词汇课...【参考方案3】:

正如您所提到的 - 后增量“i++”。声明 - “返回 i++;”返回原始值后将在内存中设置'i'的值。

尝试使用“return ++i;”也许你会得到它。

【讨论】:

我不认为这是正确的。语句 return i++; 递增 i,然后返回 i 的前一个值,即 0。我从 Eric Lippert 的回答中获得该信息:***.com/questions/3346450/…

以上是关于有趣的面试练习结果:return、post increment 和 ref 行为 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

面试题练习

练习题

关于$.ajax()、$.get()、$.post()获取return值得问题

面试题练习

练习09.09|Java编程笔试面试题

尚学堂练习9.7|Java编程笔试面试题