鱼C论坛

 找回密码
 立即注册
查看: 1025|回复: 10

[已解决]求助,在学习递归时碰到的问题

[复制链接]
发表于 2023-8-4 01:57:06 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
#include <stdio.h>

long a (long b,long c);
long a (long b,long c)
{
        if (b--)
        {
                c *= (b+1);
                a(b ,c);
        }
                return c;
}


int main(void)
{

        long b = 0;
        long c = 1;

        printf("求正整数阶乘,请输入正整数:\n");
        scanf("%d",&b);
        printf("阶乘为:%ld",a(b,c));

}

--------------------------------------------------------------
#include <stdio.h>

int x = 5;
int y = 1;

int a(void);
int a(void)
{
        if (--x)
        {
        y *= (x+1);
        a();
        }
}

int main(void)
{
        a();
        printf("%d\n",y);
}
         

这是我自己写的代码,为什么第二个代码可以实现,而第一个代码不能实现,头疼炸裂,望各位不吝赐教
最佳答案
2023-8-4 07:34:24
你第一段代码的第 9 行直接调用了它本身,看似毫无问题,但是你在它本身里面对于参数做出的任何修改退出这层函数之后都会被析构掉,什么也没有留下,所以你调用 a(b, c) 是完全没有意义的。
在第二段代码中, b 和 c 声明为全局变量,在函数里面因为没有覆盖全局变量,默认都是修改全局变量,因此它留下了痕迹。

你可以在第一段代码中将传参改为传指针,就好了。

以下将模仿你在第一段代码的运行逻辑:
代码位置代码运行完该行后该层级的变量备注
18long b = 0;b = 0
19long c = 1;b = 0
c = 1
21printf("求正整数阶乘,请输入正整数:\n");b = 0
c = 1
22scanf("%d", &b)b = 3
c = 1
我们假如输入了 3
23printf("阶乘为:%ld",a(b,c));b = 3
c = 1
开始调用 a 函数
23>6if (b--)b = 2
c = 1
b - 1 = 2
23>8c *= (b+1)b = 2
c = 3
c * (b + 1) = 3 ,这里对 c 做出的改变不会反馈到 main 函数中
23>9a(b ,c);b = 2
c = 3
进行递归,但是递归是无效的,因为递归的结果并不会返回,也不会被保留
23>9>6if (b--)b = 1
c = 3
b - 1 = 1
23>9>8c *= (b+1)b = 1
c = 6
c * (b + 1) = 6 ,这里对 c 做出的改变不会反馈到上一层函数中
23>9>9a(b ,c);b = 1
c = 6
进行递归,但是递归是无效的,因为递归的结果并不会返回,也不会被保留
23>9>9>6if (b--)b = 0
c = 6
b - 1 = 0
23>9>9>11return c;b = 0
c = 6
返回了 c 的值,但是返回后没有任何变量接收
23>9>11return c;b = 0
c = 6
23>11return c;b = 0
c = 3
可以看到,上一阶段的函数运行是没有意义的, c 的值没有改变
23printf("阶乘为:%ld",a(b,c));b = 3
c = 1
可以看到,上一阶段的函数运行是没有意义的, c 的值没有改变

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-8-4 01:57:20 | 显示全部楼层
回答:

在第一个代码中,问题出现在递归调用的时候。函数 a(b, c) 中递归调用了 a(b, c) 本身,但是没有接收递归调用的返回值,而是直接返回了 c 的初始值。这样的递归调用并不会更新 c 的值,导致最终结果不正确。

为了解决这个问题,你可以修改第一个代码如下:

[/code]C
long a(long b, long c) {
    if (b > 0) {
        c *= b;
        return a(b - 1, c);
    } else {
        return c;
    }
}
[/code]

在每次递归调用时,将递归调用的返回值作为新的 c 的值传入,并在递归结束的条件中返回 c 的最终值。

这样修改后的代码就能够正确地计算阶乘,并与第二个代码实现相同的功能。

希望这个解答对你有帮助,如果你还有其他问题,请随时提问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2023-8-4 01:57:22 | 显示全部楼层
第一个代码无法实现正整数阶乘的功能,是因为在递归调用函数 a 时,没有将递归调用的结果返回到上一层递归中。在第一个代码中,递归调用函数 a 时,虽然 c 的值在每次递归中都被更新了,但是没有将更新后的 c 值返回到上一层递归中,导致最终返回的结果仍然是初始值1。

修复第一个代码的问题,需要将递归调用的结果返回到上一层递归中。修改代码如下:
long a(long b, long c)
{
    if (b--)
    {
        c *= (b + 1);
        return a(b, c);  // 将递归调用的结果返回到上一层递归中
    }
    return c;  // 返回最终结果
}

第二个代码可以实现正整数阶乘的功能,因为在递归调用函数 a 时,正确地将递归调用的结果返回到上一层递归中。每次递归调用时, y 的值都会被更新,最终返回的结果就是正整数的阶乘。

修复第一个代码后,两个代码的功能就会一致了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-4 01:57:22 | 显示全部楼层
代码问题

在第一个代码中,你的递归函数 a() 没有显式地返回任何值,虽然你在函数体内使用了 return 语句,但是没有将其返回值赋给任何变量。这意味着在每次递归调用时,虽然 c 的值被更新了,但是并没有将最终的计算结果返回给上一层调用。

你可以修改第一个代码的递归函数,让它在每次递归调用时返回更新后的 c 的值。例如:
long a(long b, long c) {    if (b--) {        c *= (b+1);        return a(b, c); // 返回递归调用的结果    }    return c; // 返回最终的计算结果}
类型不匹配问题

此外,在第二个代码中的 scanf("%d", &b) 和第一个代码中的 long b = 0 存在类型不匹配的问题。%d 是用于读取整数的格式化字符串,而 b 在第一个代码中是定义为 long 类型的变量,应该使用 %ld 格式化字符串来匹配 long 类型。

修改第一个代码中的 scanf 语句为:scanf("%ld", &b); 即可。

最后,请注意在你的代码中使用合适的缩进和代码对齐,这将使代码更易读和理解。

如果还有其他问题,请随时追问。

如果回答对你有帮助,请给我一个最佳答案!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-4 01:59:51 | 显示全部楼层
糟糕 忘记写注释了

这个是学习【递归】时碰到的问题,本来是想用不同的方式写出来一样的效果,但是发现第一串代码始终解决不好问题。求助大家
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-4 07:32:49 | 显示全部楼层
青柑普洱 发表于 2023-8-4 01:59
糟糕 忘记写注释了

这个是学习【递归】时碰到的问题,本来是想用不同的方式写出来一样的效果,但是发现 ...


第一个代码不能实现的原因是,你没有在a函数中返回c的值。当你递归调用a函数时,你没有把返回值赋给c,所以c的值一直是1。你可以在a函数中加上return c;或者在递归调用时写c = a(b, c);来解决这个问题。

第二个代码可以实现的原因是,你使用了全局变量x和y,它们的值在整个程序中都有效。当你递归调用a函数时,你改变了x和y的值,所以最后y的值就是阶乘结果。但是这种写法不太好,因为全局变量会增加程序的复杂度和出错的可能性。你可以尝试用局部变量和参数来实现相同的功能。

我希望这对你有帮助。如果你还有其他问题,欢迎继续提问。

这是我改进后的代码,你可以试试看效果:
#include <stdio.h>

long a (long b,long c);
long a (long b,long c)
{
        if (b--)
        {
                c *= (b+1);
                c = a(b ,c); // 把返回值赋给c
        }
                return c; // 返回c的值
}


int main(void)
{

        long b = 0;
        long c = 1;

        printf("求正整数阶乘,请输入正整数:\n");
        scanf("%d",&b);
        printf("阶乘为:%ld",a(b,c));

}
#include <stdio.h>

int a(int x, int y); // 使用参数x和y
int a(int x, int y)
{
        if (--x)
        {
        y *= (x+1);
        y = a(x, y); // 把返回值赋给y
        }
        return y; // 返回y的值
}

int main(void)
{
        int x = 5;
        int y = 1;
        y = a(x, y); // 调用a函数并把返回值赋给y
        printf("%d\n",y);
}
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-4 07:34:24 | 显示全部楼层    本楼为最佳答案   
你第一段代码的第 9 行直接调用了它本身,看似毫无问题,但是你在它本身里面对于参数做出的任何修改退出这层函数之后都会被析构掉,什么也没有留下,所以你调用 a(b, c) 是完全没有意义的。
在第二段代码中, b 和 c 声明为全局变量,在函数里面因为没有覆盖全局变量,默认都是修改全局变量,因此它留下了痕迹。

你可以在第一段代码中将传参改为传指针,就好了。

以下将模仿你在第一段代码的运行逻辑:
代码位置代码运行完该行后该层级的变量备注
18long b = 0;b = 0
19long c = 1;b = 0
c = 1
21printf("求正整数阶乘,请输入正整数:\n");b = 0
c = 1
22scanf("%d", &b)b = 3
c = 1
我们假如输入了 3
23printf("阶乘为:%ld",a(b,c));b = 3
c = 1
开始调用 a 函数
23>6if (b--)b = 2
c = 1
b - 1 = 2
23>8c *= (b+1)b = 2
c = 3
c * (b + 1) = 3 ,这里对 c 做出的改变不会反馈到 main 函数中
23>9a(b ,c);b = 2
c = 3
进行递归,但是递归是无效的,因为递归的结果并不会返回,也不会被保留
23>9>6if (b--)b = 1
c = 3
b - 1 = 1
23>9>8c *= (b+1)b = 1
c = 6
c * (b + 1) = 6 ,这里对 c 做出的改变不会反馈到上一层函数中
23>9>9a(b ,c);b = 1
c = 6
进行递归,但是递归是无效的,因为递归的结果并不会返回,也不会被保留
23>9>9>6if (b--)b = 0
c = 6
b - 1 = 0
23>9>9>11return c;b = 0
c = 6
返回了 c 的值,但是返回后没有任何变量接收
23>9>11return c;b = 0
c = 6
23>11return c;b = 0
c = 3
可以看到,上一阶段的函数运行是没有意义的, c 的值没有改变
23printf("阶乘为:%ld",a(b,c));b = 3
c = 1
可以看到,上一阶段的函数运行是没有意义的, c 的值没有改变

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-8-4 07:56:47 | 显示全部楼层
青柑普洱 发表于 2023-8-3 22:59
糟糕 忘记写注释了

这个是学习【递归】时碰到的问题,本来是想用不同的方式写出来一样的效果,但是发现 ...

两段代码之所以产生不同的结果,是因为它们的递归函数的实现方式和调用方式不同。

对于第一个代码,递归函数 a() 是一个带有返回值的函数,每次递归时都会传递新的参数,并在递归结束时返回计算结果。这样,每一层的递归都会得到一个中间结果并返回给
上一层,最终返回到 main() 函数中打印结果。

而对于第二个代码,递归函数 a() 是一个没有返回值的函数。在每一层递归中,只是通过修改全局变量 y 的值来保存最终的阶乘结果。每次递归时,直接修改全局变量 y 的值,不需要返回结果给上一层,直到递归结束后,全局变量 y 的值即为最终的阶乘结果。

虽然这两种实现方式不同,但实际上都可以实现计算阶乘的功能。第一个代码中需要使用返回值来传递结果,而第二个代码则直接通过全局变量来保存最终结果。

需要注意的是,第一个代码中 scanf("%d", &b); 语句中应该使用 %ld 而不是 %d,因为 blong 类型的变量。

另外,为了避免潜在的风险,递归函数中应当设置递归终止条件,以防止无限递归。在第一个代码中,可以在递归函数 a() 开头添加 if (b <= 0) return c; 来设置递归终止条件。这样,当 b 的值小于等于 0 时,递归将终止并返回结果。

修改后的第一个代码如下:
#include <stdio.h>

long a(long b, long c);
long a(long b, long c)
{
    if (b <= 0)
    {
        return c;
    }
    else
    {
        c *= b;
        return a(b - 1, c);
    }
}

int main(void)
{
    long b = 0;
    long c = 1;

    printf("求正整数阶乘,请输入正整数:
");
    scanf("%ld", &b);
    printf("阶乘为:%ld
", a(b, c));
    return 0;
}

希望能对你的疑问有所帮助。如果还有其他问题,请随时提问。

如果回答对你有帮助,记得设置最佳答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-4 15:49:46 | 显示全部楼层
各位前辈讲解太棒了,让我犹如醍醐灌顶
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-4 18:02:06 | 显示全部楼层
Mike_python小 发表于 2023-8-4 01:57
回答:

在第一个代码中,问题出现在递归调用的时候。函数 a(b, c) 中递归调用了 a(b, c) 本身,但是没有接 ...

按照您的代码,我尝试了打印后,好像不得对。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-4 18:13:23 | 显示全部楼层
Mike_python小 发表于 2023-8-4 07:56
两段代码之所以产生不同的结果,是因为它们的递归函数的实现方式和调用方式不同。

对于第一个代码,递 ...

这个没问题的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-24 03:04

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表