1.函數又叫方法,是指實現某項功能或完成某項任務的代碼塊
//函數的主體從大括號開始,從大括號結束
//函數組成
//main函數,是給系統調用的函數
//函數組成: 返回值, 函數名, 傳入參數
//如: 實現兩個整數相加,返回它們的和
void show(void)
{
printf("hello world!\n");
}
int add(int x, int y)
{
return x+y;
}
int main(int argc, const char * argv[])
{
int val;
show();
val = add(3, 5);
printf("%d\n",val);
return 0;
}
//函數組成: 函數名 函數接口 函數體 返回值
//函數調用
//帶參數的函數
//函數的返回值就是函數運行的結果
//形式參數也叫參變量,實際上就是變量
//實際參數是實際存在的數值
//形參相當於函數中定義的變量,調用函數傳遞參數的過程相當於定義形參的變量用實參的值來初始化
//我們把在函數內部定義的變量稱爲局部變量
void print_time1(int hour, int minute)
{
printf("%02d:%02d\n", hour, minute);
printf("%p %p\n", &hour, &minute);
}
void print_time2(int hour, int minute)
{
print_time1(hour, minute);
printf("%p %p\n", &hour, &minute);
}
int main(int argc, const char *argv[])
{
int hour, minute;
hour = 12;
minute = 43;
printf("%p %p\n", &hour, &minute);
print_time2(hour,minute);
return 0;
}
局部變量就是在函數體內部聲明的變量,它只在函數體內部有效,也就是說只能在本函數內部使用它,在本函數外是不能使用的,只有在函數被調用的使用,變量纔會在內存上分配空間,調用結束,內存釋放;
測試局部變量每次分配內存位置不確定
全局變量是在函數體外部定義的變量(包括main函數),它不屬於哪個函數,而是屬於源程序,因此全局變量可以爲程序中得所有函數調用,它的有效範圍從定義開始到源程序結束;
全局變量的生命很長,它在程序的整個執行過程中都佔用內存,當程序結束時,該變量的"壽命"才結束,系統這才釋放它所佔用的內存
全局變量的缺點:值容易被修改
作用域,局部變量的作用域是從變量的定義開始到右大括號結束,全局變量的作用域是從變量的定義開始到源程序的結束
函數的聲明及定義
函數的聲明就是告訴編譯器知道有什麼樣的函數存在,可以在後面找到它,假如沒有聲明,那麼就有可能會出現找不到函數的錯誤
庫函數的使用: 條用庫函數時 , 需要包含庫函數的頭文件
2.函數的遞歸調用
一個函數在它的函數體內調用它本身,稱之爲遞歸函數
C語言中允許遞歸調用, 遞歸調用中,主調函數又是被調函數
爲了防止遞歸無終止進行,必須在函數體內有終止遞歸調用的條件
常用的辦法就是加條件判斷語句,滿足某種條件後就不在遞歸調用,逐層返回
數學上有這樣的定義 n的階乘等於n乘以n-1的階乘,n-1的階乘等於(n-1)*(n-2)!
這樣下去永遠也沒有完,所以需要定義一個基礎條件
基礎條件: 0的階乘爲1
n! = n*(n-1)!
0! = 1
因此 3! = 3*2! = 3*2*1!= 3*2*1*0!= 3*2*1 = 6;
正因爲有了基礎條件,纔沒有無休止的進行下去
那麼我們用程序怎麼樣去實現呢
一個過程或函數在其定義或說明中又直接或間接調用自身的一種方法,它通常把一個大型複雜的問題層層轉化爲一個與原問題相似的規模較小的問題來求解,遞歸策略只需少量的程序就可描述出解題過程所需要的多次重複計算,大大地減少了程序的代碼量。遞歸的能力在於用有限的語句來定義對象的無限集合。用遞歸思想寫出的程序往往十分簡潔易懂。
一般來說,遞歸需要有邊界條件、遞歸前進段和遞歸返回段。當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。
注意:
(1) 遞歸就是在過程或函數裏調用自身;
(2) 在使用遞增歸策略時,必須有一個明確的遞歸結束條件,稱爲遞歸出口,否則將無限進行下去(死鎖)。
遞歸算法一般用於解決三類問題:
(1)數據的定義是按遞歸定義的。(Fibonacci函數)
(2)問題解法按遞歸算法實現。(回溯)
(3)數據的結構形式是按遞歸定義的。(樹的遍歷,圖的搜索)
遞歸的缺點:
遞歸算法解題的運行效率較低。在遞歸調用的過程當中系統爲每一層的返回點、局部量等開闢了棧來存儲。遞歸次數過多容易造成棧溢出等。
int factorial(int n)
{
if (n==0)
{
return 1;
}
else
{
int recurse = factorial(n-1);
int result = recurse * n;
return result;
}
}
//斐波那契數列
//1 1 2 3 5 8 13 21 34 55 89 144 ....
int fibonacci(int n)
{
if (n==0||n==1) {
return 1;
}
else {
int val = fibonacci(n-1) + fibonacci(n-2);
return val;
}
}
eg.編寫遞歸函數求兩個正整數a和b的最大公約數(GCD,Greatest Common Divisor),使用Euclid算法!
//如果a除以b能整除,則最大公約數是b。
//
//否則,最大公約數等於b和a%b的最大公約數。
//
//Euclid算法是很容易證明的,請讀者自己證明一下爲什麼這麼算就能算出最大公約數。最後,修改你的程序使之適用於所有整數,而不僅僅是正整數。
int euclid(int a, int b)
{
if(a%b==0)
{
return b;
}
else
{
return euclid(b, a%b);
}
}
eg.趣味問題——年齡。有5個人坐在一起,問第五個人多少歲?他說比第4個人大2歲。問第4個人歲數,他說比第3個人大2歲。問第三個人,又說比第2人大兩歲。問第2個人,說比第一個人大兩歲。最後問第一個人,他說是10歲。請問第五個人多大?用遞歸算法實現
int age(int n)
{
if (n==1) {
return 10;
}
else{
return age(n-1)+2;
}
}