標籤:c語言 編程 遞迴 函數 參數
理解:
想用好函數應該對函數有一個充分的理解,如果不能充分理解函數,運用起來也會容易產生問題。關於函數的理解大家可以參考這篇部落格:函數再理解!。下邊就在下邊在運用上做一些相關說明。
參數: 參數傳遞:
首先說明在C語言中函數參數的傳遞都是以傳值的方式調用的。要實現在其他語言中看似傳址的功能,那麼把要操作的數所在的地址這個數當做參數傳遞就可以了。其實說白了所有的傳遞都是數的傳遞,只不過傳址傳遞的是地址資料罷了。就如同所有的數組其實都是一維的,只是為了用的方便人們人為的將其分為了二維和多維的罷了。
可變參數列表:
我們一般用的函數都是一定的參數和類型,但是例如有時候傳遞的參數的數量和類型需要使用者在運行軟體期間擷取,那麼就需要可變的參數列表了。
可變參數列表是通過stdarg這個宏來實現的。這個宏定義在stdarg.h標頭檔,同時定義了一個va_list類型和va_start、va_arg、va_end三個宏。在定義的函式宣告可如下形式:
<span style="font-size:24px;">函數名(int n_values,…)</span>
其中1、va_start用來初始化,參數為va_list變數名和省略符號前最後一個有名參數。2、va_arg用來訪問和返回參數,參數為va_list變數名和參數列表的下一個參數類型。3、va_end用來在最後取完所有參數後從函數返回,參數是va_list變數名。
運用之——遞迴:
說到遞迴大家都已經很熟悉,簡單的定義就是直接或間接調用自身的函數。但是我們經常拿來說明遞迴的例子:計算階乘和斐波那契數列的例子其實並不可以從根本上來說明遞迴功能的真正目的。
下邊就是我們常用來說明遞迴的常式:用遞迴實現計算n的階乘。
<span style="font-size:24px;">/***用遞迴方法計算n的階乘*/longfactorial(int n){if( n <= 0 )return 1;elsereturn n * factorial( n - 1 );}</span>
但是這樣用遞迴是有缺陷的,其中因為其中每次對函數的遞迴調用都會產生很多運行時開銷;其實如果函數在遞迴調用返回之後不再執行任何任務,那麼這個遞迴函式完全可以用迭代計算來替換,當然前提是需要在可讀性和運行開銷上做一定的權衡。下邊就是上邊的程式用迭代方法實現的過程。
<span style="font-size:24px;">longfactorial(int n){int result = 1;while( n > 1 ){result *= n;n -= 1;}return result;}</span>
其實針對這個例子來看,兩者的可讀性差不太多,但是後者的運行開銷要比前者少很多。由此看來後者要優於前者,但是那麼什麼時候應該用遞迴呢?看看下邊的這個程式:接受一個整型值(無符號),將其轉化為字元列印。
<span style="font-size:24px;">/*** 接受一個整型值(無符號),轉化為字元並列印。*/#include <stdio.h>voidbinary_to_ascii( unsigned int value ){unsigned int quotient;quotient = value / 10;if( quotient != 0 )binary_to_ascii( quotient );putchar( value % 10 + '0' );}</span>
這個程式和第一個程式對比可以發現,這個程式中函數在調用自身之後還做了一些其他的操作,而第一個程式則什麼也沒有做。對比可以發現更能體現遞迴強大功能的是,在函數中當函數調用自身之後,即在每一層函數被調用返回之後還需要對返回資訊做進一步操作的時候更適合用遞迴。要深入理解這一點需要從根本上理解遞迴這個東西。
C語言提高之——函數運用(參數、遞迴)