代码1
#include <stdio.h>
int f(int *a, int b)
{
b = b - 1;
if(b == 0) return 1;
else {
*a = *a+1;
return *a + f(a, b);
}
}
int main() {
int X = 5;
printf("%d\n",f(&X, X));
}
考虑下面的 C 代码。问题是预测输出结果。从逻辑上讲,我得到了 31 作为输出。(机器输出)
当我将返回语句更改为
return f(a, b) + *a;
我逻辑上得到了37。(机器输出)
我的一个朋友说,在计算返回语句时:
return *a + f(a, b);
我们在树的深度遍历过程中计算a的值,即*a先被计算,然后调用f(a, b)
函数,而在...
return f(a,b) + *a;
返回时解决,即先计算f(a,b)
,然后调用*a
。
采用这种方法,我尝试自己预测以下代码的输出:
代码2
#include <stdio.h>
int foo(int n)
{
static int r;
if(n <= 1)
return 1;
r = n + r;
return r + foo(n - 2);
}
int main () {
printf("value : %d",foo(5));
}
对于 return(r+foo(n-2));
从逻辑上讲,我得到14作为输出结果 (在机器上的输出结果)
对于 return(foo(n-2)+r);
我得到17作为输出结果。(在机器上的输出结果)
然而,当我在我的系统上运行代码时,我在两种情况下都得到17。
我的问题:
- 我朋友给出的方法是否正确?
- 如果是,为什么我在机器上运行代码2时得到相同的输出?
- 如果不是,请问解释代码1和代码2的正确方法是什么?
- 是否存在未定义的行为,因为C不支持传递引用?尽管可以使用指针实现它,但它在代码1中被使用?
简而言之,我只想知道如何正确预测上述4种情况的输出。
return *a + f(a, b);
(和return f(a, b) + *a;
)中各项的计算顺序未定义,并且该函数修改了a
指向的值,因此您的代码具有未定义的行为,任何答案都是可能的。请注意不要改变原文的意思。 - Jonathan Leffler(a + b)
,它取决于编译器(而不是语言)先评估a
还是b
;语言对这些术语的评估顺序没有任何要求。 - Jonathan Leffler*a
,因此你无法确定将添加什么值到调用函数的结果中。 - Jonathan Leffler*a
进行评估并调用函数f()
,或先调用f()
再评估*a
。编译器不需要以任何一致或可预测的方式在这些选项中进行选择,但如果代码引用了未定义行为,则不允许完全任意地运行。 - supercat