有人可以解释这个C ++程序。结果很奇怪:(

时间:2015-07-22 10:07:31

标签: c++ c++11 visual-c++ c++14

这是测试中的问题。我希望结果是1:1,但运行它并得到答案1:5,虽然我已经在Visual C ++ 2013中调试它,并看到地址的价值,这是一个' a'指向是1(最后一个' 1'在1:1中)

#include <iostream>
using namespace std;
int fact(int *a)
{
    if (*a <= 1)
    {
        return a[0];
    }
    else
    {
        return a[0] * fact(&(--*a));
    }
}
int main()
{
    int *a = new int;
    *a = 5;
    cout << fact(a) << ":" << *a;
    return 0;
}

3 个答案:

答案 0 :(得分:3)

为什么在只使用本地值时需要更改赋值给函数的值?

int fact(int a)
{
    if (a < 2)
    {
        return a;
    }
    else
    {
        return a * fact(a-1);
    }
}

答案 1 :(得分:2)

您的程序有未定义的行为。所以它可以做任何事情。

你的“完整表达”

a[0] * fact(&(--*a));
cout << fact(a) << ":" << *a;

每个人都没有定义的对象访问权限(a[0]&amp; *a)和副作用(--*a&amp; fact(a)) 。这违反了标准的§1.9/ 15:

  

除非另有说明,否则

[运营商?:&&||,]

  

对单个运算符的操作数和单个表达式的子表达式的评估是不确定的。

  

如果对标量对象的副作用相对于任何一个都没有排序   (a)对同一标量物体的另一副作用
  或
  (b)使用相同标量对象的值进行的值计算,
  行为未定义。

请参阅this answer及其问题。 (我从标准中得到了这个引用。)

可以猜测,可以检测到此违规的编译器会使fact返回1而不会影响*a,以便fact(*a)返回1而*a返回5但这只是猜测,代码可以做任何事情。 (您可以查看汇编代码以了解正在发生的事情。)

具有您想要的行为的程序涉及更多临时,更简单的语句,更简单的功能规范和更简单的程序结构。编写正确的代码是不难的,如果你知道什么不写,并检查你没有写它。为了帮助你:

  • 设置编译器选项以报告更多警告和错误,并读取其输出(许多未定义的行为可以并且可由编译器静态检测)
  • 当你读到&amp;写明确标识输入&amp;每个函数的输出规范和(子)表达式/语句
  • 明确教育自己好的设计
  • 明确教育自己的语言

答案 2 :(得分:0)

这取决于编译器。他们如何处理临时工。运营商的价值观和先发制人。 例如:在solaris CC上,输出为24:1。在一些编译器上它将是120:5。

正确答案必须是120:1。这是如何

事实要求:5 别的一部分。 a [0]:5返回值= 5 * fact(4)= 120

事实要求:4 别的一部分。 a [0]:4返回值= 4 * fact(3)= 4 * 6 = 24

事实要求:3 别的一部分。 a [0]:3返回值= 3 * fact(2)= 3 * 2 = 6

事实要求:2 别的一部分。 a [0]:2返回值= 2 * fact(1)= 2 * 1 = 2

事实要求:1
如果是部分。 a [0] = 1返回值= 1