遞迴函式,可變引數列表

audience_fzn發表於2018-08-04

遞迴

1.什麼是遞迴?

遞迴就是函式或過程在其定義或宣告的中有直接或間接呼叫自身的一種方式。他通常將一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解。

2.遞迴的主要思想:大事化小

求第n個斐波那契數(不考慮溢位)

int fib(int n)
{
	if (n <= 2)
		return 1;
	return fib(n-1) + fib(n - 2);
}

求n的階乘:

int factorial(int n)
{
	if (n <= 1)
		return 1;
	else
		return n*factorial(n - 1);
}

不允許建立臨時變數,求字串長度

int my_strlen(char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

3.遞迴的倆個必要條件

  • 存在限制條件,當滿足這個限制條件的時候,遞迴便不在繼續(遞迴要有出口)
  • 每次遞迴之後越來越接近這個限制條件

4.遞迴的缺點

  • 系統分配給程式的棧空間是有限的,單數如果出現了死迴圈,死遞迴等問題,就可能導致一直開闢空間,最終產生棧空間耗盡的情況,這樣的現象我們叫做棧溢位
  • 遞迴雖然使程式的可讀性強,思維邏輯更清晰,但其效率低

5.如何解決上述問題:

  • 將程式由遞迴改為非遞迴
  • 在遞迴內部使用static(棧物件)物件代替非static區域性變數(棧物件),這樣就不用頻繁的去申請和釋放棧空間
  • 建議使用第一種方法

可變引數列表

c語言可以通過可變引數列表來實現一個函式,使得函式可以接受一個以上任意多個引數(不固定)

  • 在函式定義的時候引數列表至少明確的定義一個引數,其餘的可變引數列表用...表示

實現一個求平均數的函式,給的任意的數字,求他們的平均數

int average(int n, ...)
{
	va_list arg;
	int i = 0;
	int sum = 0;
	va_start(arg, n);
	for (i = 0; i < n; i++)
	{
		sum = sum + va_arg(arg, int);
	}
	return sum / n;
	va_end(arg);
}
int main()
{
 	int a = 1;
	int b = 2;
	int c = 3;
	int vag1 = average(2, a, c);
	int vag2 = average(3, a, b, c);
	printf("vag1 = %d\n", vag1);
	printf("vag2 = %d\n", vag2);
	system("pause");
	return 0;
}

//用n表示接收引數的個數,...表示可變引數列表

  • 可變引數列表要通過四個巨集來輔助完成

1)這四個巨集的標頭檔案#include<stdarg.h>

2) va_list,用來宣告一個變數,變數的型別為va_list,他用於訪問引數列表未確定的部分

3)這個變數是呼叫va_start來初始化的,va_start(arg,n)他的第一個引數是va_list的變數名,第二個引數是省略號前最後一個有名字的引數,初始化過程把arg變數設定為指向可變引數部分的第一個引數

4)為了訪問引數,需使用va_arg,這個巨集接受倆個引數,va_list變數和引數列表中下一個引數的型別

5)最後,當訪問完最後一個可變引數之後,我們需要呼叫va_end,將指標置空

 

  • 注意事項:

1)引數列表必須從頭到尾逐個訪問,如果你訪問了幾個就想終止,或者是一開始就緒從中間訪問,都是不行的。

2)這些巨集都沒有辦法檢查引數型別,如果在使用va_arg時指錯了引數型別,後果不堪設想

3)這些巨集無法直接判斷實際存在引數的數量

 

可變引數的實現過程其實就是使用這些巨集來輔助完成的

 

 

 

相關文章