2016-12-29 29 views
1

我剛剛開始學習C,我決定在練習中使用一些Euler Problems。 不工作的程序旨在解決Problem2,它要求計算所有甚至低於4,000,000的斐波納契數的和。C中的遞歸只在打印不相關的東西時才起作用

這個程序真的很奇怪,它實際上工作,但只有當我在遞歸過程中打印某些東西時:每當我嘗試在遞歸函數中註釋printf("bazooka");行時,我會得到看起來完全隨機的結果,正數和大負數(例如-882154758和770491113)在連續執行同一程序時。另一方面,如果我打印某些東西,無論如何,在遞歸函數中,我會得到正確的輸出。

我覺得這種行爲非常奇怪和有趣,我真的很想知道發生了什麼事情:真正讓我困惑的是,即使程序沒有被修改,輸出的數字也會改變。另外,我不明白爲什麼在遞歸期間打印應該對正在執行的整數計算有任何影響。

這是我的主要功能:

int first = 1; int second = 2; int total = 0; 
total = Fibo(first,second, total); 
printf("\nthis is my result for Euler 2: "); 
printf("%d",total); 

這是我的遞歸函數:

int Fibo(int first, int second, int total) { 
    printf("bazooka"); 
    if (second < 4000000) { 
    int add; 
    second = first+second; 
    first = second-first; 
    if (first%2 == 0) { 
     add = first; 
    } 
     total = add+Fibo(first,second,total); 
    } 
    return total; 
} 

任何人可以幫助我弄清楚了這一點?我非常感謝你的幫助。

+6

你需要初始化'int add = 0;'。否則,它可以(顯然確實)把它存儲在'total = add + Fibo'(第一,第二,總計)行中的任何值寫入' – UnholySheep

+1

即使使用你的'bazooka'修復程序,I得到'-1900183196'。當然這是錯誤的。 – usr2564301

+1

遞歸函數是完全過度銷燬的。將這種技術用於更難的問題。一個簡單的循環就可以做到。由於限制是4000000' int'對於32位機器已經足夠了。 –

回答

6

add如果first是奇數,則不會初始化。確保在兩種情況下初始化變量,並且錯誤將消失。

現在,解釋觀察到的行爲:使用未初始化的變量可以顯示爲隨機的「值」,否則可能導致程序以其他隨機方式發生故障。 (類似C語言的技術術語是undefined behavior。)在你的情況中,這個值可能是上一次使用函數堆棧幀的內存位置時遺留的垃圾,或者是上一次使用的寄存器。調用printf可能會解決問題,因爲它的實現恰好使用並清除了相關的內存部分。不用說,這不是你可以依賴的東西。

請注意,此類錯誤將由編譯器通過適當的警告設置進行診斷,例如GCC或Clang的-Wall

-3

好了,我可以不涉及100%有關的行爲,但是可以肯定,當你得到像負數的數字,是因爲你超出int值的最大值:

INT_MIN = -2147483648 
INT_MAX = +2147483647 

改變這種類型如果得到相同的結果,則爲longlong long

Here您可以檢查數據類型邊界。

+1

這是一個公平的猜測,但正如你從其他答案中看到的,這不是原因。檢查這是否是問題的一個好方法是實際打印出中間值;這樣做表明它永遠不會達到那麼高。 – usr2564301

+0

碰巧,'int'對於[問題]是足夠的(https://projecteuler.net/problem=2)。 –

+1

忽略我之前的評論,看起來鏈接中顯示的值很奇怪,並不是很有代表性。我比較喜歡[cppreference](http://en.cppreference.com/w/c/types/limits)在cplusplus.com上的原因之一 - 信息通常更準確。 (另外'INT_MIN'和'INT_MAX'實際上並不是常量,它們依賴於編譯器) – UnholySheep