注册 登录
编程论坛 C++教室

关于递归求自然数列和

勇敢坚毅 发布于 2017-09-02 21:12, 2520 次点击
求自然数列N各位的和如N==4,sum=4+3+2+1=10;
代码如下:
 4 int main(void)
 5 {
 6    printf("fun:%d\n",func(4));
 7 }
 8
 9
 10 int func(int num)
 11 {
 12     if(num==0)
 13         return 0;
 14     return num+func(num-1);
 15 }
 
代码的运行结果是:10,这是正确的。
将第14行改为return num+func(--num);后结果输出是错误的6,这是为什么?
在棧中调用时 num-1 与 --num不是一样的吗?
求各位大神帮忙解答一下。
系统是linux:redhat 7.2
内核版本:3.10.0-327.el7.x86_64
编辑器用的是VIM
9 回复
#2
勇敢坚毅2017-09-02 21:53
自己顶下
#3
zghnxzdcx2017-09-02 22:20
num+func(num-1)在num=4的时候,执行完func(num-1)之后,num值没有改变,还是4;
num+func(--num)在num=4的时候,执行完func(--num)之后,num已经变成3了,--num是先自减后调用函数
老师留的思考题,要动动脑子……


[此贴子已经被作者于2017-9-2 22:23编辑过]

#4
rjsp2017-09-03 17:56
num+func(--num)
未定义行为
#5
rjsp2017-09-04 10:53
以下是引用rjsp在2017-9-3 17:56:01的发言:

num+func(--num)
未定义行为

g++8.0 报
warning: operation on 'num' may be undefined

clang6.0 报
warning: unsequenced modification and access to 'num'
#6
zghnxzdcx2017-09-04 21:52
回复 5楼 rjsp
大哥,那是递归函数里的一条语句,单独拿出来,你在逗我吗?
#7
rjsp2017-09-05 08:57
回复 6楼 zghnxzdcx
你看不懂,但学过C或C++的别人看得懂
num+func(--num) 这个表达式属于“未定义行为”,就这么简单,有什么看不懂的呢?哦,我猜估计是不知道什么叫“未定义行为”,其它语言中确实没这概念。

程序代码:
#include <cstdio>

int func( int num )
{
    return num;
}

int main( void )
{
    int num = 0;
    int val = num+func(--num); // ------ 违反了“修改之后只许读一次”的限定
    printf( "%d\n", val );
}

无论是g++,还是clang,在编译时都会警告 num+func(--num) 这一句属于“未定义行为”
g++说的是 operation on 'num' may be undefined
clang说的是 unsequenced modification and access to 'num'
输出结果也各不相同,当然了,既然是“未定义行为”,那任何结果都没有意义。

BTW: 给有兴趣学C/C++的人介绍一下C/C++中的三种需要注意的行为

实现定义(implementation-defined)行为:
比如 char是有符合还是无符号,不同的编译器的行为不一样。

未指定(unspecified)行为:
比如 fun(a,b) 中是先求解a表达式还是b表达式,即使是同一个编译器,都可能各处不一样。

未定义(undefined)行为:
比如 ++i + ++i,编译器完全不认为有人会写出这样的代码,因此也从不考虑出现这种代码的可能。
gcc曾经就搞怪过一次,一旦代码中出现这种行为,就自动开启某个游戏。这样做是符合C/C++标准的。

总结一下:
实现定义行为:不同的编译器的行为不一样,但在同一个编译器中,可以保证一致。
未指定行为:在同一个编译器中都不能保证一致,但不管结果对错,起码有一个确定的结果。
未定义行为:连一个确定的结果都不能保证,可能输出一个错误的结果,也可能直接格式化掉你的硬盘。
#8
delphier_bc2017-09-06 21:47
return num+func(num-1)
return num+func(--num)
先不考虑未定义行为的问题,我觉得这个应该涉及到运算优先级的问题吧
#9
zghnxzdcx2017-09-06 22:46
回复 7楼 rjsp
    这的确不是正常人能写出的代码,求自然数列的和,可以用n(n+1)/2,,可以用循环,这俩都比递归效率高。
    很明显,这是老师在教++ 、 -- 运算符优先级的时候“设计”的题目。
    在这种“设计”的过程中,一般老师只考虑C语言的基础语法,而不考虑高级编译器对代码的限制。
    因为有一种东西叫做Turbo C,可以满足老师对入门学生的随意刁难……

[此贴子已经被作者于2017-9-6 23:05编辑过]

#10
rjsp2017-09-07 08:41
回复 9楼 zghnxzdcx
num+func(--num) 中有优先级相关的内容吗?第一层只有一个加号,没有两个及以上的操作符自然不需要什么优先级,第二层前者是个变量表达式,后者是--,也只有一个操作符。
再者,优先级 是指“结合”的优先级,比如 a+b*c,因为*比+的优先级高,所以 a+b*c 等同于 a+(b*c),而非 (a+b)*c。优先级和表达式评估先后顺序无关,对于 a+(b*c),C/C++从未规定过先评估a表达式,还是先评估(b*c)表达式。

以 num+func(--num) 为例,C/C++ 从未规定过第一个num值是执行 --num 之前的值,还是之后的值。
仅仅如此也就罢了,只是输出一个不确定的值。见7楼内容,它属于大名鼎鼎的“未定义行为”!
1