5

如果 p 的值在调用前被初始化为 5,那么 f(p,p) 的返回值是多少?请注意,第一个参数是通过引用传递的,而第二个参数是通过值传递的。

int f (int &x, int c) {
       c = c - 1;
       if (c==0) return 1;
       x = x + 1;
       return f(x,c) * x;
}

选项是:

  1. 3024
  2. 6561
  3. 55440
  4. 161051

我试图解释:


在这段代码中,将有四个递归调用,参数为 (6,4)、(7,3)、(8,2) 和 (9,1)。最后一次调用返回 1。但是由于通过引用传递,之前所有函数中的 x 现在都是 9。因此, f(p,p) 返回的值将是 9 * 9 * 9 * 9 * 1 = 6561。


这个问题来自竞争性考试 GATE,(参见 Q.no.-42)。答案键由 GATE “Marks to all”给出(意味着没有正确的选项。)key set-C, Q.no.-42。某处解释为:

在 GATE 2013 中,所有人都获得了标记,因为 C/C++ 中的相同代码会产生未定义的行为。这是因为*不是 C/C++ 中的序列点。正确的代码必须替换

return f(x,c) * x;

 res = f(x,c);
 return res * x;

但是给定的代码工作正常。GATE的钥匙错了吗?或者真的是问题的错误?

4

2 回答 2

14
   return f(x,c) * x;

此操作的结果取决于评估这两个事物的顺序。由于您无法预测它们将被评估的顺序,因此您无法预测此操作的结果。

于 2015-09-30T08:47:04.370 回答
9

C++03第5章:

除非另有说明,否则未指定单个运算符的操作数和单个表达式的子表达式的求值顺序,以及副作用发生的顺序。

因此,在 的情况下f(x,c) * x,操作数的求值顺序是未指定的,这意味着您不知道是左操作数还是右操作数首先被求值。

您的代码具有未指定的行为,这意味着它将以某种定义的方式运行,只有编译器知道。程序员不知道代码会做什么,只知道它要么先计算左操作数,要么先计算右操作数。出于优化目的,甚至允许编译器根据具体情况更改评估顺序。

如果评估顺序很重要,则需要重写代码。依赖于未指定行为的代码始终是一个错误,可能是一个不会立即浮出水面的非常微妙的错误。

未指定的行为不同于未定义的行为,这意味着任何事情都可能发生,包括程序失控或崩溃。

于 2015-09-30T08:56:06.450 回答