一個真正的程序裏面白喊自定義函數,也包含對應的頭文件,還有函數定義界面。因而建立了個簡單的加法函數。
函數的聲明數組
#ifndef __ADD_H__ #define __ADD_H__ //函數的聲明 int Add(int x, int y); #endif
我將這個聲明放在目錄爲add.h的文件下,其中的網絡
#ifndef __ADD_H__ #define __ADD_H__ #endif
做用是爲了防止函數連續被調用時整個函數的定義段被連續搬運,致使主程序的代碼量過大。函數的調用原理是,講函數定義目錄下的代碼通過頭文件搬運到須要用的地方,而後執行。
函數的定義ide
int Add(int x, int y) { return (x + y); }
放在目錄爲add.c的目錄下,將對應功能的函數放在具備提示意義的目錄下面,可以與他人更好的配合,具備可讀性。
主函數模塊化
#include <stdio.h> #include "add.h" int main() { int a = 15; int b = 25; printf("sum=%d\n",Add(a, b)); return 0; }
引用自定義函數的頭文件時,用的是雙引號 "" 。函數
#include <stdio.h> int main() { printf("haha\n"); main(); return 0; }//遞歸常見的錯誤,棧溢出,stack overflow
這是一個沒有限制條件的遞歸,程序運行一下子就會本身中止,而且彈出警告窗口,緣由是,程序運行的時候,會將運行時產生的局部變量存在名爲堆棧的一個內存區域,這個沒有限制的遞歸,不斷的調用自身,不斷的打印「haha」,就會將堆棧佔滿。
而這個程序也讓人能理解,遞歸,就是函數對於自身的調用,用如今的網絡流行語,俗稱套娃。設計
void print(int n) { if (n > 9) { print(n / 10); } printf("%d ", n % 10); } #include <stdio.h> int main() { int num = 0; scanf("%d", &num); print(num); return 0; }
第一次要使用遞歸進行實現某一個功能實際上是 很沒有頭緒的,儘管聽老師講完了 ,程序也跟着打了出來,也看着調試一步步的調了,眼看着代碼一行一行的走,尤爲是函數裏面的調用,到了最後一層,不知足調用條件的時候,程序運行窗口就一個一個的把字符打印出來了,我前期是比較沒有理解,程序執行到這個地方是怎麼一層一層的返回去的,就是忘記了程序執行到了哪裏,老師畫圖講解以後,纔算是明白,一層一層的進來,也是要一層一層的出去。當最後一層再也不知足條件執行完畢彈出以後,彈出到上一層以後,繼續執行下一條語句,以此類推。指針
先是寫一個能實現求字符串從長度的函數,不考慮遞歸
最簡單的固然是直接使用庫函數計算字符串長度調試
#include <string.h> int main() { strlen(); }
接下來用自定義函數code
int my_strlen(char* str) { int count = 0; while (*str != '\0') { count++; str = str + 1; } return count; }
整個字符串是沒法直接被函數調用的,只能講字符串的地址做爲指針變量,指向字符串的第一個字符,調用進入函數之中,每次用完以後+1,直到看到‘\0’字符,字符串的長度計算中止。count就做爲一個計數,記錄字符串的長度。但是咱們須要的是一個不用臨時變量的函數實現這一功能。遞歸
#include <stdio.h> int my_strlen(char* str) { if (*str != '\0') return 1+my_strlen(str + 1); else return 0; }//未使用臨時變量進行計數,實現了求字符串長度 int main() { char arr[] = "bit"; int len = my_strlen(arr);//傳送過去的是數組第一個元素的地址,並非整個數組 printf("len = %d\n", len); return 0; }
遞歸仍是同樣,用畫圖的方法解釋起來更容易理解,將程序執行的過程可視化,加強理解,有必定的限制條件,並且每一層調用函數都在使得限制條件更加接近不知足if語句,最終可以中止遞歸過程。俗稱中止套娃。
當理解了前面兩個遞歸的例子以後,我也獨立寫出了這個求階乘的遞歸代碼,大概思路爲,想要求出n!,先要求出(n-1)!,想要求出(n-1)!,先要求出(n-2)!,快進到想要求出2!,就先求出1!,因此仍是對自身的不斷調用,代碼以下:
#include <stdio.h> int Fac1(int n) { int num = 1; int i = 0; for (i = 1; i <= n; i++) { num = i * num; } return num; } int Fac2(int n) { int ret = 1; if (n != 0) ret = n * Fac2(n - 1); else return ret; } int main() { int n = 0; scanf("%d", &n); printf("%d!=%d\n",n, Fac1(n)); printf("%d!=%d\n",n, Fac2(n)); return 0; }
其中也用了個for循環寫了另外一個函數實現目的。
斐波那契數列,1 1 2 3 5 8...簡單的說,就是想知道第n個,就得先知道第n-1個和第n-2個,要知道第n-1個和第n-2個,就得知道第n-2和n-3個,第n-3和n-4個...以此類推,但是遞歸求第n個,須要運算的次數,就是2^n+2^(n-1)+...+2^2+2次運算,當求到第40個以上的時候,程序已經有了很明顯的等待,須要等待才能出結果,計算的次數其實已經很大,n每+1,運算次數就會多出兩倍,運算時間也會多出兩倍,代碼以下:
#include <stdio.h> int Fib1(int n) { if (n <= 2) return 1; else return Fib1(n - 1) + Fib1(n - 2); } int Fib2(int n) { int a = 1, b = 1, c=0; int i = 0; if (n > 2) { for (i = 3; i <= n; i++) { c = a + b; a = b; b = c; } return c; } else return 1; } int main() { int n = 0; scanf("%d", &n); int f2 = Fib2(n); printf("第%d個斐波那契數列:%d\n", n, f2); int f1 = Fib1(n); printf("第%d個斐波那契數列:%d\n", n, f1); return 0; }
因此以上代碼中還有一個,不用遞歸,直接用迭代實現的函數,一運行就能看到,兩個函數實現目標的時間差,因此當,遞歸之中函數調用的次數過大時,運算量巨大,就頗有必要使用其餘手段實現目標。