【问题标题】:Decrement Operator in C++C++中的递减运算符
【发布时间】:2014-04-19 17:54:26
【问题描述】:

我来自 C 背景,现在我正在使用 C++ 学习 OOP

下面是一个计算阶乘的程序。

#include <iostream>

using namespace std;

void main ()
{
    char dummy;
    _int16 numb;
    cout << "Enter a number: ";
    cin >> numb;

    double facto(_int16);

    cout << "factorial = " <<facto(numb);
    cin >> dummy;
}

double facto( _int16 n )
{
    if ( n>1 )
        return ( n*facto(n-1) );
    else
        return 1;
}

上面的代码运行良好。

但是如果我替换return语句

    return ( n*facto(n-1) );  

有了这个

    return ( n*facto(n--) );

然后它不起作用。 n-- 不会将 n 减 1。为什么?

我正在使用 Visual Studio 2012

编辑:知道了!谢谢:)
*另外,我想补充以下答案:使用 --n 将导致 n 在语句执行之前递减。因此,由于预减量,表达式将变为 (n-1)*facto(n-1) 。这就是为什么在这种情况下最好不要使用预减量 *

【问题讨论】:

  • "n-- 不会将 n 减 1" - 不正确。下次验证你的假设。注意:它就像在 C 中一样工作。
  • 鉴于最近的安全警报,您可能希望开始在 if 块周围使用 {}。另外,using namespace std 是错误的形式。
  • @AlexChamberlain 什么安全警报?
  • n*facto(n--) 是未定义的行为。叮当说warning: unsequenced modification and access to 'n'
  • @TomFenech:谷歌搜索“goto fail”,这是最近的一个例子。添加第二行很容易,但忘记添加大括号,最终会在不应该的情况下无条件地执行代码。 (在这种情况下,它会导致重要的安全检查被绕过。)

标签: c++ function recursion operator-keyword


【解决方案1】:

编辑:: 下面的解释只是为了阐明 Post 和 Pre-Decrement 的用法,以便 OP 更好地理解它们。 OP 代码的正确答案是, n*facto(n - 1)。 @OP:你不应该在你的代码的那部分做任何预先准备,因为它会因为变量n的无序修改而调用未定义的行为。

前后减量:: 如果要在传递值之前递减变量,则必须使用预递减 (wiki-link)。另一方面,后减量会在变量减量之前计算表达式:

int n = 10, x;
x = --n;                // both are 9

int n = 10, x;
x = n--;                // x = 10, i = 9

为什么不在你的情况下使用预减量?:: n*facto(n--) 导致 UB为什么?

§5/4 中的标准说

在上一个和下一个序列点之间,一个标量对象应该 有它的存储值修改最多一次的评估 表达。

只能访问先验值以确定要使用的值 存储。

这意味着,在两个序列点之间,一个变量不能被多次修改,如果一个对象被写入一个完整的表达式中,那么在同一个表达式中对它的任何和所有访问都必须直接参与计算要写入的值。

【讨论】:

    【解决方案2】:

    目前,通过使用n--,您将n 的原始值传递给facto,从而导致循环。

    您需要改用n - 1。从表面上看,使用--n 会很诱人,因为这会减少n 并评估为新的(较低的)值。但是--n 会给您未定义的行为,因为您将函数返回值预乘以n,并且由于* 不是序列点,因此该值n 的定义不明确。

    (顺便说一句,C 中的行为是相同的)。

    [编辑:在未定义的行为点上确认 Mike Seymour]。

    【讨论】:

    • 不,您不需要使用--n。这在这里给出了未定义的行为(因为有第二次无序访问n);并且n 的值在此之后未使用,因此无论如何修改它的值是没有意义的。应该是n-1
    • @Paranaix 对,但在函数调用之前还是之后评估 n* 的左操作数)?
    • 我认为(并且可能是错误的),函数调用确保递减发生在 (i) 函数调用和 (ii) @987654338 左侧的 n 评估之前@.
    • @Bathsheba: 不。例如,它可以在没有排序的情况下评估n--n,然后调用函数,然后评估* 的结果。
    • 好的。我会修改答案。
    【解决方案3】:

    return ( n*facto(n--) );

    您正在使用后减运算符。 发生的情况是,您将 n 的值传递给函数,然后递减它。这不会影响已经传递给函数的值

    【讨论】:

    • 请查看有关“未定义行为”的其他答案
    • @DieterLücking:这是从问题中复制代码以描述错误的原因,而不是建议使用此代码。 (未定义的行为是错误的第二个原因,但不是特别相关。)
    猜你喜欢
    • 2015-10-03
    • 1970-01-01
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 2011-02-16
    • 2014-03-21
    • 2019-03-15
    相关资源
    最近更新 更多