当前位置:C++技术网 > 资讯 > C语言溢出问题,看一下这两个程序代码有什么区别

C语言溢出问题,看一下这两个程序代码有什么区别

更新时间:2016-08-13 00:07:29浏览次数:1+次

问题:

Fibonacci数列的递推公式为:Fn=Fn-1+Fn-2,其中F1=F2=1。

当n比较大时,Fn也非常大,现在我们想知道,Fn除以10007的余数是多少。

下面是我写的代码:

#include<stdio.h>

int Fab(int n)
{
int result;
if(n==1||n==2)
result=1;
else
result=(Fab(n-1)+Fab(n-2));
return 0;
}
int main()
{

int n;
scanf("%d",&n);
printf("%d",Fab(n)%1007);
return 0;

}
测试数据22时输出的数据不正确,但在8,9,或者10等小范围内的输出数据是正确的,网上说是因为先算出数值再求余,数值太大了发生溢出。下面是网上搜的正确代码:

#include<stdio.h>
int main(){
int n,i,f1=1,f2=1,f3;
scanf("%d",&n);
for(i=3;i<=n;i++)
{
f3=(f1+f2)%10007;//看这里!!!!!!!!!!!!!!它不也是先求出数值(f1+f2)再求余(f1+f2)%10007么?
f1=f2;
f2=f3;
}
printf("%d\n",f3);
return 0;
}

问题在代码旁边。我不懂为什么他那样写就不会溢出,不是同样都是先求出数值再求余么?

C++技术网解答:

    从代码的功能实现逻辑来看,两个代码都是先求值,再求余。这是没有异议的。同时,溢出也和求余无关。溢出发生在求值部分。你的代码用了递归实现,可能会出现栈溢出,他的代码则只是简单的数值相加,不会栈溢出。

    分析两个代码的不同,你的代码使用的是递归形式来求值,测试数据小的时候,递归次数是比较少的。测试数据大的时候,递归次数就很多了。

    每一次递归的时候,会将当前函数的状态压栈保存,以免递归返回时恢复状态。也就是说,没多一次递归,也就要多用一些内存,所以测试数据大的时候,递归次数达到一定次数后,消耗的内存就超过了你使用的栈的内存大小,也就发生了栈溢出。

    而默认的栈是1MB,很多次递归后,这1MB也就被消耗殆尽,然后就溢出,最后会导致程序崩溃。这也就是为什么递归不被常用的原因。

    但是如果你确实需要用递归解决问题,因为有时候递归最方便,所以你还是要用递归。那么出现这个栈溢出的问题如何解决呢?

    解决栈溢出,最直接能够想到的就是增加栈大小,一直增加到你使用的正常情况不会产生溢出位置。但是总有一个限制的,不可能无限增大的。在VS中可以设置默认的栈的大小。在项目属性中的【链接器Linker】->【系统System】->【堆栈保留大小Stack Reserve Size】,如下图所示(这是中文版VS2010设置界面,英文版见后面的单词):

    另外一个解决办法,就是再改善代码,减少每一次递归的函数内的局部变量,将不必要的变量去掉,这样也给每次压栈减轻负担,这样同样大小的栈,可以支持更多次的递归。

    以上两种方法都是用来解决栈溢出的问题的。