如果p的值为在调用之前初始化为5?请注意,第一个参数是通过引用传递,而第二个参数通过值传递。
int f (int &x, int c) { c = c - 1; if (c==0) return 1; x = x + 1; return f(x,c) * x; }
选项包括:
- 3024
- 6561
- 55440
- 161051
我试着解释:
在这段代码中,将有四个参数为(6,4(、(7,3(、(8,2(和(9,1(的递归调用。最后一个调用返回1。但由于通过引用,以前所有函数中的x现在都是9。因此,f(p,p(返回的值将是9*9*9*1=6561。
这道题来自竞争性考试GATE(见Q.no.42(。答案由GATE给出"全部打分"(意味着没有正确的选项。(密钥集-C,Q.no.42。某处解释为:
在GATE 2013中,由于C/C++中的相同代码会产生未定义的行为,因此对所有代码都进行了标记。这是因为*
不是C/C++中的序列点。正确的代码必须替换
return f(x,c) * x;
带有
res = f(x,c);
return res * x;
但是给定的代码运行良好。GATE的钥匙错了吗?还是这个问题真的错了?
return f(x,c) * x;
此操作的结果取决于评估这两件事的顺序。由于无法预测它们的评估顺序,因此无法预测此操作的结果。
C++03第5章:
除非另有说明,否则单个运算符的操作数和单个运算符的子表达式的求值顺序表达式,以及副作用发生的顺序,都没有具体说明。
因此,在f(x,c) * x
的情况下,操作数的求值顺序是未指定的,这意味着您不知道左操作数还是右操作数将首先求值。
您的代码有未指定的行为,这意味着它将以只有编译器才知道的特定定义方式进行行为。程序员不知道代码会做什么,只知道它会先计算左操作数,或者先计算右操作数。编译器甚至可以根据具体情况更改评估顺序,以达到优化目的。
如果评估顺序很重要,则需要重写代码。依赖于未指定行为的代码总是一个bug,可能是一个非常微妙的bug,不会立即出现。
未指定的行为不同于未定义的行为,这意味着任何事情都可能发生,包括程序失控或崩溃。