【问题标题】:Can anybody explain the error in the program i made, can anybody why i didn't workout?谁能解释我制作的程序中的错误,谁能解释我为什么不锻炼?
【发布时间】:2016-04-12 19:01:30
【问题描述】:

今天过得怎么样 :), 看看下面的程序,下面写的程序是计算前n个自然数的和,问题是我得到了n-1个自然数的和,谁能解释一下为什么?

任何人都可以解释为什么a--而不是--a。

#include<stdio.h>
main()
{
    int a,sum;
    printf("Enter a number.");
    scanf("%d",&a);
    sum=sumnat(a);
    printf("Sum of the first %d natural numbers is %d.",a,sum);
}
sumnat(a)
{
    int b;
    if(a==0)
    {
        return 0;
    }
    else
    {
        b=a+sumnat(--a);
        return(b);
    }
}

【问题讨论】:

  • 传入-1,你会溢出堆栈,因为它会永远递归
  • @self,但这在这个网站上很正常!
  • 你读过代码吗? a == 0 是递归的出口点
  • 是的,但为什么 a-- 不起作用,只有 --a
  • 如果您仍在使用像 main() 这样没有返回类型的东西,并且正在为定义变量和初始化变量之间的区别而苦苦挣扎——您最好花时间学习语言的基础知识而不是担心递归和未定义的行为。

标签: c debugging


【解决方案1】:

有几个错误,其中最大的错误是使用a 的表达式中的未定义行为以及修改后的值a。您还应该正确定义您的函数,而不是依赖编译器提供的默认值。

#include <stdio.h>

int sumnat(int a);                  // function prototype

int main(void)                      // correct signature
{
    int a, sum;
    printf("Enter a number. ");
    scanf("%d", &a);
    sum = sumnat(a);
    printf("Sum of the first %d natural numbers is %d.", a, sum);
    return 0;
}

int sumnat(int a)                   // function has a return type and argument type
{
    if(a == 0)
    {
        return 0;
    }
    return a + sumnat(a - 1);       // there was no need to decrement `a`
}

节目环节

Enter a number. 5
Sum of the first 5 natural numbers is 15.

【讨论】:

  • @WeatheVane 非常感谢,我终于找到了缺陷,事实是直到最后(或最后)递归发生在表达式 b=a+sumnat( - 一个);不返回,当它返回时,它是 0 ,因为条件 if(a==0) return 0;也因为参数的执行是从右到左进行的。
  • 我怎么强调都不过分,b=a+sumnat(--a)未定义的行为。如果它在一台计算机上工作,它被称为“幸运”。
  • @WeatherVane ..或“不幸”取决于你的迂腐程度。
【解决方案2】:

您的程序适用于我,在 Mac OSX 上使用 gcc。但是,由于这条线,它不会在任何地方都有效:

b=a+sumnat(--a);

--a 递减a,但如果在加法之前这样做,那么你的结果将是错误的。我不确定 C 是否需要严格从左到右评估表达式(我不认为是这样)。无论如何,由于您不在该行之后使用a,您可以通过以下方式解决问题:

b=a+sumnat(a-1);

正如@self 所说,您应该修复程序以处理负值,并且最好考虑一下您可以通过这种方式计算其和的最大自然数是什么(以及为什么会这样)。

【讨论】:

  • 如果我使用 - - 为什么程序会无限递归?
  • [回复已删除的评论,抱歉] 是的。我只是不想声称这绝对是错误的,因为我不是最新的 C 标准。这样做当然是一个非常糟糕的主意,但据我所知,最近的标准更新使其合法化。不过,关于b 的初始化,我认为这并没有错。这当然不是最佳实践,但他没有使用未初始化的值(他只是没有在首选时间初始化它)。整个子程序可以替换为return (a &lt;= 0) ? 0 : a + sumnat( a - 1 );
  • a-- 是一个 post 减量。在您从sumnat() 返回之前,a 的值实际上并没有递减。
  • 换句话说,如果a = 1sumnat(a--)本质上与sumnat(a); a--;相同,那么您将永远无法成功递减a并最终陷入无限循环。
  • @ChristopherSchneider 非常感谢你,这就是我所需要的。事实是,直到最后一次(或最后一次)递归发生,表达式 b=a+sumnat(--a) 中的 a 值;没有返回,当它返回时,它是 0,哇,我很激动,太棒了。
【解决方案3】:

它们之间是有区别的。一个第一个从 a 中减去,然后进入函数,而另一个第一个进入......所以它永远不会被减去,你会进入 inifinit 堆栈。

【讨论】:

    【解决方案4】:

    "还有谁能解释为什么用 a-- 而不是 --a"

    当您使用前缀运算符 --a 时,减少在其他任何事情之前完成,而后缀运算符 a-- 发生在表达式的其余部分被解析之后,所以,可以说,在调试代码时,在特定时刻,a = 5 因为这条线

    b=a+sumnat(--a);
    

    使用前缀版本的运算符,减量会立即发生,使a=4,然后函数 sumnat 将被调用,参数为 4

    b=a+sumnat(a--);
    

    在这种情况下,使用后缀运算符,因此首先将使用参数 5 调用函数 sumnat,因为那是那一刻 a 的值,然后,只有当函数返回一个值时(它永远不会在您的示例中发生,因为它会以相同的值被多次调用,永远不会达到 0)会发生递减

    【讨论】:

    • 为什么要either 后缀或前缀。只需使用b = a + sumnat(a-1)
    猜你喜欢
    • 2021-11-27
    • 2019-06-23
    • 1970-01-01
    • 1970-01-01
    • 2021-07-02
    • 2014-01-09
    • 2020-06-17
    • 1970-01-01
    • 2014-09-22
    相关资源
    最近更新 更多