【0007】函式
阿新 • • 發佈:2020-07-31
函式的結構
#include <stdio.h> // 函式的別稱是方法,函式是完成某一特定功能的模組 void print() // 自定義函式 { printf("鋤禾日當午 \n"); // printf是系統函式 /* 函式名 printf 函式的引數 "鋤禾日當午 \n" () 緊挨著函式名之後,包含引數 */ getchar(); // 等待輸入一個字元 } void printadd(int自定義函式的結構a, int b) { printf("a+b=%d", a+b); // 將a+b的值轉換為字串,對映到字串“a+b=%d” } // 函式就是加工廠,給你輸入,你給我輸出;但是函式的輸入與輸出可以為空 void main1() //C程式的入口,有且僅有一個main函式 { //print(); // 自定義函式 //printf("鋤禾日當午 \n"); // printf是系統函式 printadd(4, 8); getchar(); }
函式名與函式表
#include <stdlib.h> #include <stdio.h> // int getmax中的int是函式的返回值型別 // getmax即函式名,是一個指向常量的指標,指向程式碼區的函式表某個地址;記錄了函式名對應的函式體的入口地址(每一個應用程式都有一個函式表,該表儲存了該程式所有函式的入口地址——即函式名對應的地址,改變函式入口地址可以改變函式的行為) // int a, int b函式的形式引數 // {...} 塊語句,不允許省略 // return a > b ? a : b; 返回值 // int getmax(int a, int b) 函式宣告,別稱函式頭函式名與函式表int getmax(int a, int b) { /*int a; */ // error C2082 : redefinition of formal parameter 'a' , 函式體內的變數和函式引數是同級別的同屬函式體 return a > b ? a : b; } void main02() { printf("%p", getmax); getchar(); } /* 在下面語句的下方打一斷點: printf("%p", getmax); 0017133E 查詢反彙編:位址列輸入0x0017133E 跳轉到該程式的函式表對應的: _getmax: 0017133E jmp getmax (01717A0h) 在函式表中 即函式名getmax對映到getmax()函式體的位置0x01717A0 位址列輸入0x01717A0 跳轉到了函式體的記憶體位置: 函式實體 int getmax(int a, int b) { 001717A0 push ebp 001717A1 mov ebp,esp 001717A3 sub esp,0C4h ... */
函式的定義與宣告
#include <stdlib.h> // std標準庫,C語言標準庫是跨平臺的 #include <stdio.h> #include <Windows.h> // 僅適用於Windows系統(第三方庫函式) // C++屬於嚴格的程式語言,函式的宣告必須在呼叫之前 int getres(int a, int b, int c); // 函式的宣告 /* 呼叫一個函式,首先必須知道這個函式是存在的C語言自上而下編譯 被調函式沒有定義或者其在主調函式之後時,編譯會出錯 故解決的方法有: 首先要定義這個被調函式 其次被調函式如果在主調函式之後,則需要在主調函式之前對被調函式加以宣告;如果被調函式在主調函式之前則不需另加宣告 */ // 函式的宣告 void msg(); // 函式的宣告,只是說明函式的存在,因此也可出現重複(傻子才這麼幹) void msg(); void msg(); void msg(); int cheng(int a, int b); void main123() { msg(); printf("%d \n", cheng(12, 3)); system("pause"); } // 函式的定義 void msg() { MessageBoxA(0, "鋤禾日當午", "學Cztm刺激", 0); } //void msg() error C2084: function 'void msg()' already has a body; note: see previous definition of 'msg' //{ // 函式的定義則只能出現一次 //} int cheng(int a, int b) { return a + b; } void main124() { // 程式碼重用 int x = 3, y = 6, z = 9; x = x*x*x; y = y*y*y; z = z*z*z; int res = x + y + z; res = getres(x, y, z); /* getres(x, y, z);呼叫在定義之前時 C程式: warning C4013: 'getres' undefined; assuming extern returning int 1>LINK : fatal error LNK1561: entry point must be defined (C中能編譯——僅是警告,但是連結不行——嚴重錯誤:例項處必須定義) CPP程式: 1>LINK : fatal error LNK1561: entry point must be defined 2>error C3861: 'getres': identifier not found */ int a = 10, b = 13, c = 14; a = a*a*a; b = b*b*b; c = c*c*c; int res1 = a + b + c; res1 = getres(a, b, c); system("pause"); } int getres(int a, int b, int c) { return a*a*a + b*b*b + c*c*c; } void run(char *path) // 外部函式,C語言功能的實現(程式碼重用)主要靠函式 { ShellExecuteA(0, "open", path, 0, 0, 1); } void main01() { run("E:\\Thunder Network\\Thunder\\Program\\Thunder.exe"); getchar(); /* 庫函式: 由C語言系統提供,使用者無需定義,也不必在程式中做型別說明,只需在程式前包含有該函式定義的標頭檔案即可 */ }函式的呼叫與宣告
#include <stdlib.h> #include <stdio.h> int add05(int, int); // 函式宣告 /* 宣告時,變數名可省略,可以多次宣告 函式的型別宣告應該和定義的函式的型別保持一致,否則編譯器會報錯 當被調函式定義在主調函式之前,宣告就沒必要了 */ void main005() { add05(3, 2); system("pause"); } int add05(int a, int b) { return a + b; }宣告時,形參變數名可省略,可以多次宣告
函式的引數
#include <stdio.h> #include <stdlib.h> /* 形參(形式引數)與實參(實際引數)的總結: 形參: 1、函式呼叫之前,形參即函式定義時()裡的引數,值是不確定的; 2、不確定的值,不會分配記憶體,只有呼叫的時候,才會分配記憶體並新建一個變數,新建的這個變數(形參)會接收實參(實際引數)的值,當函式呼叫結束之後,形參所佔據的記憶體會被回收 實參: 1、函式呼叫時,主調函式傳遞給被調函式的確切值就是實際引數,實參可以是常量、變數或者表示式 形參與實參記憶體地址不一樣,佔用的是不同的記憶體空間 */ // 地址不一樣,說明change(int num)與main()函式中的num是2個不同的變數 // 函式定義的時候是形參 void change(int num) // 此處的int num,是int型別的變數,是形參,只有在函式change被呼叫的時候才會分配記憶體,change執行完畢,num的記憶體即被回收;函式呼叫的時候,形參分配記憶體,新建一個num的變數,用於儲存傳遞過來的實際引數的值 { printf("change=%x, num=%d \n", &num, num); // change = 17824956, num=10 num = 100; printf("change=%x, num=%d \n", &num, num); // change = 17824956, num=100 } void main11() { int num = 10; printf("main=%x, num=%d \n", &num, num); // main = 17825168, num=10 change(num); // 此處的num是一個實參,函式呼叫的時候傳遞的是實參;實參可以是變數、常量或表示式 printf("%d \n", num); // 10 system("pause"); }形參與實參
#include <stdlib.h> #include <stdio.h> /* 函式呼叫的時候,形參分配記憶體 新建一個變數,儲存傳遞過來的實參的值,等價於實參給形參賦值,賦值會自動完成資料型別轉換 */ void print_1(int num) { printf("num=%d \n", num); } int adddata(int a, int b) { return a + b; } void main12() { // 呼叫函式的時候,儘量做到型別匹配,否則可能導致誤差或錯誤 //print_1(10.8); double db = adddata(10.9, 9.8); printf("%lf \n", db); // 19.000000 double db2 = adddata("Ahg", "fgB"); // Warning C4047 'function': 'int' differs in levels of indirection from 'char [4]' ----> C // Warning C4024 'adddata': different types for formal and actual parameter 1 ----> CPP printf("%lf \n", db2); // 11990992.000000 意想不到的結果 system("pause"); }對應的形參與實參型別應一致
函式的可變引數
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> void myprintf(char *ptstr, ...) // 可變引數 { va_list ap; // 定義起始點 (char *型別的指標) va_start(ap, ptstr); /* 固定引數pstr,是函式myprintf()的第一個引數,儲存於棧中,位於棧底 typedef char * va_list; 把 n 圓整到 sizeof(int) 的倍數 #define _INTSIZEOF(n) ( (sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1) ) 初始化 ap 指標,使其指向第一個可變引數。v 是變參列表的前一個引數 即 此處的ptstr #define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) 該巨集返回當前變參值,並使 ap 指向列表中的下個變參(ap指向的資料以type型別的方式加以解析) #define va_arg(ap, type) ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) ) 將指標 ap 置為無效,結束變參的獲取 #define va_end(ap) ( ap = (va_list)0 ) 原文連結:https://blog.csdn.net/u013490896/java/article/details/85490103 參考連結:https://www.cnblogs.com/clover-toeic/p/3736748.html */ char flag; while (*ptstr) { flag = *ptstr; if (flag != '%') { putchar(flag); ptstr++; } else { flag = *++ptstr; switch (flag) { case 'd': printf("%d", va_arg(ap, int)); ptstr++; break; case 's': printf("%s", va_arg(ap, char *)); ptstr++; break; case 'c': //printf("%c", va_arg(ap, char)); putchar(va_arg(ap, char)); ptstr++; break; case 'f': printf("%f", va_arg(ap, double)); ptstr++; break; default: break; } } } va_end(ap); // 結束讀取 } void main003() { myprintf("niha\n"); myprintf("niha%d\n", 10); myprintf("niha%d%s\n", 10, "Hello"); myprintf("niha%d%s%c\n", 10, "Hello", 'A'); myprintf("niha%d%s%f%c\n", 10, "Hello", 3.1415926, 'A'); puts("\n"); system("pause"); }函式可變引數巨集的結構
#define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <stdio.h> #include <stdarg.h> // stand argument // 已知引數的個數為num int add3(int num, ...) // ...代表可變引數,num代表引數個數 { int res = 0; //結果 va_list argp; // 儲存引數開始的地址(引數列表首地址) va_start(argp, num);// 從首地址開始,讀入num後面的資料到地址 for (int i = 0; i < num; ++i) { res += va_arg(argp, int); // 按照int型別讀取一個數據單元 } va_end(argp); return res; } void go(int num, ...) { va_list argp; va_start(argp, num); for (int i = 0; i < num; ++i) { /*char str[50]; sprintf(str, "%s", va_arg(argp, char *)); system(str);*/ system(va_arg(argp, char *)); } va_end(argp); } void showint(int start, ...) { va_list argp; va_start(argp, start); int argvalue = start; // 第一步初始化 do { printf("%d ", argvalue); argvalue = va_arg(argp, int); } while (argvalue != -1); va_end(argp); } void main08() { //printf("%d \n", add3(3, 1, 2, 3)); //6 //printf("%d \n", add3(4,3, 1, 2, 3)); // 9 //printf("%d \n", add3(5, 4, 7, 1, 2, 3)); // 17 //go(3, "notepad", "calc", "tasklist&pause"); showint(1, 2, 3, 4, 5, -1); getchar(); }函式可變引數的應用
#include <stdio.h> #include <stdlib.h> // void main(void) 返回空型別,引數為空 // main() 預設的返回值型別為int型別,引數為空 main(int argc, char *args[]) { for (int i = 0; i < argc; i++) { puts(args[i]); } // argc是引數的個數 // args[]是一個指標陣列,儲存的是常量字串的地址,args[0]第一個引數是主程式的路徑,第二個是附加引數 system("pause"); } void main020(int argc, char *args[], char *envr[]) // 第三個引數:環境變數字串的地址 { char **pp = envr; while (*pp != NULL) { puts(*pp); pp++; } system("pause"); }main函式的引數列表
函式引數的運算與入棧順序
#include <stdlib.h> #include <stdio.h> void add2(int a, int b) { printf("a=%d, b=%d \n", a, b); } void main07() { int a = 5; int b = 5; int c = 5; int d = 5; int e = 5; int f = 5; /* 函式引數與函式一樣,遵循棧先進後出的原則,即先執行的程式碼後入棧,後執行的程式碼先入棧 */ add2(a, a++); // a=6, b=5 /* 入棧: 1、a++是一個表示式,儲存在棧中的結果為5,a自增1等於6 2、a是一個變數,儲存在棧中的結果為a 出棧: 2、a ---> 6 1、a++ ---> 5 ----> 5 */ add2(b, b += 1); // a=6, b=6 /* 入棧: 1、b+=1是一個賦值表示式,儲存在棧中的結果為b,b自增1等於6 2、b是一個變數,儲存在棧中的結果為b 出棧: 2、b ---> 6 1、b+=1 ---> b ---> 6 */ add2(c++, c = c + 2); // a=7, b=8 add2(d++, d += 2); // a=7, b=8 /* 入棧: 1、d+=2是一個賦值表示式,儲存在棧中的結果為d,d自增2等於7 2、d++是一個表示式,儲存在棧中的結果為7,d自增1等於8 出棧: 2、d++ ---> 7 1、d+=2 ---> d ---> 8 */ add2(e, e++, e += 2); // a=8, b=7 /* 入棧: 1、e += 2是一個賦值表示式,儲存在棧中的結果為e,e自增2等於7 2、e++是一個表示式,儲存在棧中的結果為7,f自增1等於8 3、e是一個變數,儲存在棧中的結果為e 出棧: 3、e ---> 8 2、e++ ---> 7 因為add2()函式定義中只有2個形參,因此1、e += 2不會作為函式的引數出棧 */ add2(f += 2, f++, f += 2); // a=10, b=7 /* 入棧: 1、f += 2是一個賦值表示式,儲存在棧中的結果為f,f自增2等於7 2、f++是一個表示式,儲存在棧中的結果為7,f自增1等於8 3、f += 2是一個賦值表示式,儲存在棧中的結果為f,f自增2等於10 出棧: 3、f += 2 ---> f ---> 10 2、f++ ---> 7 因為add2()函式定義中只有2個形參,因此1、f+= 2不會作為函式的引數出棧 */ getchar(); }函式的引數的入棧順序
函式的執行過程
#include <stdlib.h> #include <stdio.h> // C語言通過棧來控制程式的執行順序,後執行的語句或函式先進棧,最後壓棧的語句或函式先出棧執行 void main06() { printf("main 上 \n"); //void print1(); // C語言理論上是要加宣告的 //print1(); 沒有宣告時,該函式無引數,會到系統中去找匹配的函式,結果沒有,就發生連結錯誤 add1(3, 4); // 而此時add1函式未加宣告,C編譯器卻編譯並連結成功,還能正確執行,只能說C編譯器太寬泛了,此處編譯器根據add1(3,4);有引數,而且返回值是整數,因此找到了被調函式 printf("%d \n", add1(3)); // 15274067(執行第二次結果就不一樣了) 引數多了或少了,結果不可預測(居然編譯併成功執行了,C編譯器真是大條了!) printf("main 下 \n"); system("pause"); } /* 被調函式的定義在主調函式之後,C語言編譯器可能找到了,則會通過編譯並連結成功;如果沒找到則會出現以下錯誤: (10): warning C4013: 'print1' undefined; assuming extern returning int (17): error C2371: 'print1': redefinition; different basic types 但是在被調之前加以宣告,則一定能找到已定義的被調函式 */ void print1() { printf("main 上 \n"); printf("main 下 \n"); } int add1(int a, int b) { return a + b; }函式的呼叫執行過程注意事項
函式呼叫的注意事項
#include <stdio.h> void main09() { //printf("Hello China. \n"); printf; // 引用函式名必須宣告 // warning C4550: expression evaluates to a function which is missing an argument list 加入#include <stdio.h>時 } /* C語言函式可以自動定位,沒有標頭檔案,沒有函式宣告,自動尋找,引數多了、少了都能執行;如果不是函式呼叫,無法自動定位 */ void main001() { //printf("%d \n", add4(2, 3)); //add4; /* 當上面一句沒有被註釋時:[compile] warning C4013: 'add4' undefined; assuming extern returning int,而且能夠連結並且程式能夠執行 當上面一句被註釋時:[compile]error C2065: 'add4': undeclared identifier 說明C編譯器查詢add4(2, 3); 時,因為有函式呼叫而且是有參呼叫,能夠精確定位到本程式內部的函式定義,接著下面的add4就在上一步的基礎上找到了。 可見C語言的編譯器太靈活了。 */ print11(); system("pause"); } int print11() { } int add4(int a, int b) { return a + b; }函式呼叫的錯誤示範
函式的返回值
#include <stdlib.h> #include <stdio.h> int go() { } /* Warning C4716 'go': must return a value 非main函式如果函式型別不是void,編譯時會出現一個警告,如果是CPP檔案,則會是一個錯誤 函式的返回值型別必須與函式名前的型別保持一致,當函式的型別為void時,可以沒有return語句 void main(void) 返回空型別,引數為空 main() 預設的返回值型別為int型別,引數為空 */ int main6() // 無論main函式是否是void型別,還是其他型別的函式,main函式可以沒有返回值 { //printf("\n1"); //printf("\n2"); //return 1; // return 之後的語句不會接著執行,main函式中的return意味著整個程式的退出和結束 //printf("\n3"); //printf("\n4"); //printf("\n5"); godata(); getchar(); // main函式或其他函式中沒有return語句,執行完所有的語句後,函式會自動退出 } /* 函式內部定義的變數或引數(區域性變數),在函式呼叫結束之後(函式返回後),變數即刻被銷燬,記憶體被回收 函式返回值有副本機制,返回的時候,另外再存一份 如果返回值是全域性變數,則該變數一直存在,直到程式執行結束,全域性變數才會被銷燬,記憶體這時才被回收 */ int addpp(int a, int b) { int z = a + b; printf("%p", &z); return z; } int addbb(int a, int b) { int z = 0; z = a + 1; z = a + 2; z = a + b; return a + b; // a+b是臨時變數,在暫存器中儲存其計算結果 // 返回臨時變數時,臨時變數會從暫存器中即刻銷燬 } void main() { // 此處列印的是副本,原來記憶體中的資料已被銷燬 //printf("%d \n", addpp(3, 7)); printf("%d \n", addbb(3, 7)); printf("\n\n"); getchar(); }函式的返回值
區域性變數與全域性變數
#include <stdio.h> #include <stdlib.h> /* 總結: 塊語句內部的變數,其作用域是變數所在塊語句定義的起始處至該塊語句的結束,也可作用於內部包含的塊語句(前提是沒有定義與該變數的名稱相同的變數——存在內層變數遮蔽外層變數的情況) 同一個塊語句不能重複定義一個變數 區域性變數呼叫完成以後會被回收,該區域性變數的位置出現垃圾資料 區域性變數是為塊語句服務的,塊語句執行結束,區域性變數就被回收 函式內部定義的變數以及函式的引數均是區域性變數 */ int a = 100; // 變數名相同的全域性變數和區域性變數,是兩個(記憶體地址)不同的變數,因此可以重複定義 void main16() { int a = 10; // 在同一塊語句內,變數不能重複定義 //int a = 11; // Error C2374 'a':redefinition int b = 99; printf("%x, %x, %d, %d \n", &a, &b, a, b); // 5bfd44, 5bfd38, 10, 99 { int a = 11; // 不同的塊語句,不同的作用域 printf("%x, %x, %d, %d \n", &a, &b, a, b); // 5bfd2c, 5bfd38, 11, 99 塊語句中可以包含塊語句,區域性變數b的作用範圍包括子塊,而在子塊中定義的變數a遮蔽了母塊中的變數a(其效果與塊語句中的變數a遮蔽全域性變數a一樣) } system("pause"); }塊語句與區域性變數
#include <stdlib.h> #include <stdio.h> // 全域性變數不屬於任何一個函式,可以被任何一個函式呼叫 // 建立的全域性變數比main函式還早,全域性變數的生存期是整個程式的生存期 // 全域性變數在程式生命週期內一直儲存於記憶體,而區域性變數在所屬的函式呼叫完畢之後生命週期結束,同時其所佔據的記憶體也將被回收 // 需要任意函式呼叫的場合就需要全域性變數,全域性變數可用於函式間的通訊 int num = 4298; // 全域性變數 -- 整個公司的RMB int data = 10; void 事業部A() { num = num - 800; // 支出800 num = num + 900; // 營收900 } void 事業部B() { num = num - 1800; // 支出1800 num = num + 900; // 營收900 } void printdata() { printf("%d \n", data); } void main14() { data = 100; printdata(); // 100 //num += 1000; // 科技創新基金 //事業部A(); //事業部B(); //printf("num=%d \n", num); system("pause"); }全域性變數
#include <stdio.h> #include <stdlib.h> /* 全域性變數特點/缺點: 生存週期一直持續到程式退出 記憶體也在程式退出之後才釋放 容易與區域性變數重名,容易被遮蔽失效 值容易被修改——例如遊戲,遇到外掛一類的程式、注入的黑客技術等技術,值容易被修改 */ /* 全域性變數可以被本檔案中所有的函式所共享 使用全域性變數要做到: 1、變數名要容易理解,儘可能不與區域性變數重名 2、避免佔記憶體較大的變數作為全域性變數 3、避免全域性變數被錯誤的修改(正規的軟體工程,寫一個函式需要修改全域性變數時,一定要註釋為什麼修改,修改的目的是什麼,修改值是多少) */ int RMB = 3000; void addRMB(int num) { RMB += num; } void mulRMB(int num) { RMB -= num; } void printRMB() { printf("你的RMB還有%d \n", RMB); } void main17() { addRMB(1000); mulRMB(5); mulRMB(500); mulRMB(5); printRMB(); system("pause"); }全域性變數的特點
#include <stdio.h> #include <stdlib.h> int x = 1000; void main15() { int x = 8; // 變數名稱相同的時候,在區域性變數的作用域中,區域性變數會遮蔽全域性變數(不是改變) printf("%d \n", x); // 8 //printf("%d \n", ::x); // C++可以用::x來訪問全域性變數x, C則不可以 system("pause"); } /* 全域性變數很容易被內部變數遮蔽,很容易被引用或修改 */ int a; void maina() { printf("%d \n", a); /* 本檔案未宣告變數a時:int a error C2065: 'a': undeclared identifier 宣告a時:int a; 輸出結果為9,int a =9;是在同工程中的“全域性變數和區域性變數.c”檔案中宣告的——說明全域性變數是可跨檔案呼叫的 */ getchar(); } void main006() // 這裡說的遮蔽是指變數名相同的變數 { int a = 10; printf("%d \n", a); // 區域性變數會遮蔽全域性變數 { printf("%d \n", a); // 10 此處是引用的上一層區域性變數 char a = 'B'; //int a = 66; // error C2371: 'a': redefinition; different basic types printf("%d,%c \n", a, a); // 內部塊語句區域性變數會遮蔽內部塊語句以外的變數 } printf("%d \n", a); // 10 getchar(); }全域性變數與區域性變數之間的衝突
#include <stdlib.h> #include <stdio.h> /* 區域性變數只有定義和初始化的概念,不存在宣告 全域性變數可以多次宣告,定義的時候相當於宣告+初始化 */ //int a = 10; // 全域性變數 int a; // 全域性變數被當成宣告來看待 int a; // 全域性變數未定義預設為ASCII為0,字元為空 int a; int a = 9; // 全域性變數的定義 //int a = 3; // error C2374: 'a': redefinition; multiple initialization void main004() { printf("%d,%c \n", a, a); // 0,' ' int b; //printf("%d \n", b); // error C4700: uninitialized local variable 'b' used printf("%c,%d \n", c, c); // ' ',0 system("pause"); } void main003() { int a; // 區域性變數 int a=13; // error C2086: 'int a': redefinition } void go001() { a = 13; //(無全域性變數時) error C2065: 'a': undeclared identifier }全域性變數與區域性變數的定義及全域性變數的宣告問題
函式與遞迴
#include <stdio.h> #include <stdlib.h> //void main() //{ // main(); // 死迴圈 //} // f(n)=f(n+1)+1 // f(5) return void go_3(int num) { if (num >= 5) return; else { system("notepad"); go_3(num + 1); } } /* 1+2+3+...+100 f(100) 1+2+3+...+99 f(99) f(100)=f(99)+100 f(n)=f(n-1)+n */ int goadd_1(int num) { if (num == 0) return 0; else return num + goadd_1(num - 1); } /* 10 % 2 0 5 % 2 1 2 % 2 0 1 % 2 1 (10)10=(1010)2 */ void to2(int num) { if (num == 0) return; else { //printf("%d", num % 2); // 0101 呼叫之前順序 to2(num / 2); printf("%d", num % 2); // 1010 呼叫之後逆序 } } void main009() { //go_3(0); //printf("%d \n", goadd_1(100)); to2(10); getchar(); }線性遞迴
#include <stdio.h> #include <stdlib.h> /* 斐波那契數列: 有一對兔子,每個月可以生育一對兔子,剛出生的兔子2個月後可以生育一對兔子,問N個月之後又多少對兔子 1 1 1 1 1 1 1 1 1 1 1 1 g(n)=g(n-1)+g(n-2) */ int getRabbitTreeRecursive(int num) { if (num == 1 || num == 2) return 1; else return getRabbitTreeRecursive(num - 1) + getRabbitTreeRecursive(num - 2); } int getRabitForCycle(int num) { int f1 = 1, f2 = 1; int f3; for (int i = 3; i <= num; ++i) { f3 = f2 + f1; f1 = f2; f2 = f3; // 輪替注意值的覆蓋順序 } return f2; } void main() { printf("%d \n", getRabitForCycle(40)); printf("%d \n", getRabbitTreeRecursive(40)); printf("%d \n", getRabitForCycle(40)); /* 樹狀遞迴速度較慢,函式的迴圈呼叫需要消耗時間,但是演算法簡單; 樹狀遞迴可以分解為:迴圈+棧 */ getchar(); }樹狀遞迴_斐波那契數列