題記:
本篇文章由乙個「有問題」的程式,帶入你進入遞迴的世界。雖然只是採用了遞迴中最簡單的型別,尾遞迴。但卻能使你馬上感受到遞迴的妙用和煩惱。希望大家由淺入深、循序漸進,更好的使用遞迴。其中又涉及了遞減運算子的使用,它同樣是讓你歡喜讓你憂!雖然使用它給你帶來高效的**,但不小心同樣讓你深陷泥潭。
1.#include
2.long fun(int );
3.int i=1,j=3;
//i,j
僅僅是為了說明遞迴時是第幾級呼叫
4.5.int main(void)
6.12.
13.long fun(int m)
14.38.else
39.42.return ans;
43.}
嘗試分析
5個可測選項會輸出什麼結果?
#1正確,依次呼叫、返回。最終效果為:
fun(0)*5*4*3*2*1
#2/3/4
表示式雖略有差異,但***相同,動作發生時間相同。
貌似可以產生正確結果但執行卻發現「
n=0」,
why?發生了什麼?這就要從遞迴的原理考慮,並對比
#1的形式。如果是
#1,在一級呼叫
fun時
(main
對fun
的呼叫)
,即fun(3),
然後這個函式呼叫還沒執行完,就執行了
fun(2)
『自身呼叫,
fun對
fun,和
#1一樣,但同時它把
m的值改變了!』
… 效果如上文所示
如果採用
#2的形式,效果:
fun(0)*4*3*2*1*0
,所以「
n=0」
#5是最複雜的,同時難於理解,最好能了解遞迴的細節、副操作、順序點等知識
(在文章最後,有簡略解釋)。
一級呼叫
fun(),
即fun(3),
注意傳遞給
fun函式時,m就是
3,而二級呼叫(呼叫自身)時,
m的值還沒改變呢
(字尾遞減
)!又是
fun(3)
。**呼叫也將是
fun(3)……
遞迴雖然有條件檢測語句
(17行
)用於結束遞迴,但
m值相當於不變,一直遞迴,知道資源耗竭為止!
是否有疑問呢?為什麼要說「相當於」呢?如果你夠細心,肯定發現了一點蛛絲馬跡!
m值其實變了,但什麼時候變了?以二級呼叫為例解釋,即第一次自身呼叫時。
fun函式呼叫時
m給了它,隨後
m變成了,這可以通過加入22、
23行**加以驗證,你會發現
m確實變成了
2。那**呼叫不就是
fun(2)
了嗎?不是!!
遞迴是個很奇妙的東西!它總能迷惑你的雙眼。
每一級函式呼叫都有自己的變數!此m
非彼m,可以從位址中發現(我在這個例項已經加入了顯示位址的語句)。
如果兩個不同的函式,可能我們很容易的就明白,兩個
m的不同
如:fun1(int m)
fun2(int m)
但換到遞迴,我們可能就摸不到頭緒了。在此建議大家:
多聯絡多思考,語言是由基本要素擴充擴充套件而來。
如遞迴不過是函式呼叫自身,那麼函式具有的特性,它也應該具有!
遞減運算子在這個程式給你帶來的
trouble
夠大嗎?所以用之勿慎!
c就是這樣,夠靈活以致可以夠高效、夠強大;靈活又使我們摔倒千次。
決定命運的關鍵
:立即行動
php fpm backlog引數潛在問題
前幾天有業務在新機器上線測試時,發現個問題 同樣的資源的虛機 同樣配置的ngxin php fpmweb後端的兩台機器,測試後發現 訪問.html檔案時qps相差不大,但是訪問php 頁面時其中一台的qps是另一台的數倍。通過分析,發現是php fpm的backlog引數引起的,可以通過設定php ...
日期格式化使用 YYYY MM dd 的潛在問題
昨天在v站上看到這個關於yyyy mm dd的使用而出現bug的帖子 v2ex.com t 633650 非常有意思,所以拿過來分享一下。在任何程式語言中,對於時間 數字等資料上,都存在很多類似這種平時一切ok,特定時間 特定環境出問題的情況。出現這種問題的根本原因還是我們對於各種資料結構的細節定義...
c 混合使用不同標準編譯潛在的問題
最近專案使用的c 的版本到c 11了,但是由於有些靜態庫 a 沒有原始碼,因此鏈結時還在使用非c 11版本的庫檔案。目前跑了幾天,似乎是沒出什麼問題,但是我還是想說一下這樣做有哪些潛在的風險。首先需要說明的是,公升級到c 11之後,部分std的資料結構的記憶體布局有可能發生改變 待考究 最開始,我認...