?
有時候,如果程序的功能比較多。規(guī)模比較大,把所有的程序代碼都寫在一個主函數(shù)中,就會使得主函數(shù)太龐雜,所以為了方便閱讀和維護(hù)程序,就引進(jìn)了 組裝程序 的概念,把某些功能都在其他分支完成,然后需要哪個功能的時候就組裝那個分支到主函數(shù),這些分支就叫它函數(shù),組裝就叫調(diào)用,這樣就會使主程序簡化了,哪個函數(shù)是做什么也都很清楚。哪里用得到這個功能就在哪個調(diào)用就可以了!
?
C 語言的函數(shù)可以直觀地辨別出面向過程和面向?qū)ο蟮膮^(qū)別,C 語言的函數(shù)有一個特點(diǎn),就是它有固定的格式和固定的模型。對于一個 C 程序而言,它所有的命令都包含在函數(shù)內(nèi)。每個函數(shù)都會執(zhí)行特定的任務(wù)。每個函數(shù)都只能被定義一次。但一個函數(shù)可以根據(jù)需要被多次的聲明和調(diào)用。
函數(shù)的定義
在使用函數(shù)之前必須先定義,后使用。
定義函數(shù)要包括:
1、指定函數(shù)的數(shù)據(jù)類型,以便后續(xù)返回值的調(diào)用
2、指定函數(shù)的名字,以便后續(xù)調(diào)用
3、指定函數(shù)形參的類型和名字,以便后續(xù)傳遞數(shù)據(jù),對于無參(void)可不用
?
函數(shù)類型+函數(shù)名+(參數(shù)表){ 函數(shù)體 }
?
參數(shù)值的()起到了表示函數(shù)調(diào)用的重要作用即使沒有參數(shù)也需要(),如果有參數(shù),則需要給出正確的數(shù)量和順序,這些值會按照一定的順序(看編譯環(huán)境一般是從右到左)依次來初始化函數(shù)中的參數(shù)
注意? 如果調(diào)用函數(shù)時給的值與參數(shù)的類型不匹配有些編譯環(huán)境可能會幫你類型強(qiáng)制轉(zhuǎn)換好,但是有可能不是你想要的那樣。所以? 建議傳遞給函數(shù)的值要與聲明一致
?
#include//這里聲明的是int的形參 int a(int a);//但是如果換成浮點(diǎn)類型輸出將會不一樣 int main(void){ double t = 23.8; a(t);//這里傳進(jìn)去的是浮點(diǎn)數(shù)(實(shí)參) } int a(int a){//這里接收到的是整型的實(shí)參 int t = a; //所以即使換成double t 也一樣 printf("%d", t);//輸出23 } //但是更高級的語言會檢查比較嚴(yán)格如 java C++
?
函數(shù)的傳值
每個函數(shù)都有自己的變量空間,參數(shù)也位于這個獨(dú)立的空間中,和其他函數(shù)沒有關(guān)系
值的傳遞:傳遞給函數(shù)的值可以是表達(dá)式的結(jié)果(包括):字面量、變量、函數(shù)的返回值、計(jì)算的結(jié)果。但是在調(diào)用函數(shù)時,永遠(yuǎn)只能傳 值 給函數(shù),在傳值的時候?qū)嶋H上只是把實(shí)參的值傳遞到形參處,做的只是一個復(fù)制的過程(但是指針就不一樣了)
在函數(shù)定義的形參中,它們是不占用內(nèi)存的,在主函數(shù)內(nèi)調(diào)用形參的值時才會被臨時分配內(nèi)存。實(shí)參給形參傳遞的是值的傳遞,屬于單向傳遞。把實(shí)參的值傳遞給形參,在調(diào)用結(jié)束后,形參的存儲單元被釋放,而形參值的任何變化都不會影響到實(shí)參的值,實(shí)參的存儲單元仍保留并維持?jǐn)?shù)值不變。
地址的傳遞:形參為指針變量時函數(shù)之間的數(shù)據(jù)傳遞,如果函數(shù)的形參為指針類型時,對應(yīng)的實(shí)參類型必須與形參保持一致
這種方式使用數(shù)組名或者指針作為函數(shù)參數(shù),傳遞的是該數(shù)組的首地址或指針的值,而形參接收到的是地址,即指向?qū)崊⒌拇鎯卧螀⒑蛯?shí)參占用相同的存儲單元,這種傳遞方式稱為“參數(shù)的地址傳遞”。
地址傳遞的特點(diǎn)是形參并不會占用存儲空間,數(shù)組名或指針就是一組連續(xù)空間的首地址。因此在數(shù)組名或指針作函數(shù)參數(shù)時所進(jìn)行的傳送只是地址傳送,形參在取得該首地址之后,與實(shí)參共同存在一個存儲單元,形參的變化也就是實(shí)參的變化。
函數(shù)的返回值
在定義的時候,如果不需要返回值的時候定義void類型,其他時候定義其他數(shù)據(jù)類型。但是使用void類型的時候,不能使用帶值的return(可以沒有return),調(diào)用的時候不能做返回值的賦值
int 和void的不同:
? ? 前面加有void 的函數(shù),不能返回任何數(shù)據(jù),這類函數(shù)應(yīng)該將所有應(yīng)該實(shí)現(xiàn)的功能在本函數(shù)內(nèi)全部實(shí)現(xiàn)。但是并不是不能與外部交換數(shù)據(jù),仍然可以通過引用型參數(shù)傳遞數(shù)據(jù),只是調(diào)用時不能直接接受返回值,因?yàn)榫蜎]有返回值。
? ? 前面有int的函數(shù),返回值是整型數(shù),可能是結(jié)果是整數(shù)的數(shù),也可能是運(yùn)行狀態(tài),成功或失敗的標(biāo)識,函數(shù)調(diào)用時可以直接利用返回信息,實(shí)現(xiàn)一些功能。
main()函數(shù)的揭秘?
main()函數(shù)原形:int main(int argc,char const*argv [ ] )
里邊的兩個參數(shù),允許從執(zhí)行環(huán)境中傳遞任意的多字節(jié)字符串 (argv[0])是命令本身,命令行參數(shù)是保存在argv[? ]里的,C/C++語言規(guī)定,可執(zhí)行程序程序本身的文件名和地址? ,其中的一個描述了命令行參數(shù)的個數(shù),通常稱為argc;另一個是命令行參數(shù)的數(shù)組,通常稱為argv。命令行參數(shù)都是字符串,所以argv的類型是char *? [argc+1]。該程序的名字也作為argv[0]傳進(jìn)來,這個參數(shù)的表總以0結(jié)束,也就是說,argv[argc]==0。(argv數(shù)組的最后一個元素存放了一個NULL的指針)
?
#includeint main(int argc, char * argv[]){ //argv[0]== 調(diào)用函數(shù)時使用的程序名和地址 //argv[1]==參數(shù)1 //argv[2]==參數(shù)2 //argv[3]==參數(shù)3 //依次類推... //argc 就是計(jì)算并保存總共有多少個參數(shù)的 int i; for (i = 0; i < argc; i++) { printf("%s ", argv[i]); } return 0; }
?
給main函數(shù)傳遞的這兩個參數(shù),argc和argv。argc是int類型的,它表示的是命令行參數(shù)的個數(shù)。不許要用戶傳遞,它會根據(jù)用戶從命令行輸入的參數(shù)個數(shù),自動確定。argv是char**類型的,它的作用是存儲用戶從命令行(黑窗口輸入)傳遞進(jìn)來的參數(shù)。它的第一個成員是用戶運(yùn)行的程序名字。
main函數(shù)的返回值,用于說明程序的退出狀態(tài)。如果返回0,則代表程序正常退出;返回其他數(shù)字的含義則由系統(tǒng)決定,通常,返回非零代表程序異常退出。(一般是由return返回)
return 的妙用
(return 是C語言的關(guān)鍵字)函數(shù)定義為什么樣的返回類型,該函數(shù)中return后就應(yīng)該是相應(yīng)類型的值。
在函數(shù)中,如果碰到return 語句,那么程序就會返回調(diào)用該函數(shù)的下一條語句執(zhí)行,也就是說跳出函數(shù)的執(zhí)行,回到原來的地方繼續(xù)執(zhí)行下去。但是如果是在主函數(shù)(main)中碰到return語句,那么整個程序就會停止。return表示從被調(diào)函數(shù)返回到主調(diào)函數(shù)或其他函數(shù)繼續(xù)執(zhí)行,返回時可 附帶一個返回值,返回值可以是一個常量,變量,或是表達(dá)式。? 傳指針形式:直接傳給函數(shù)的是變量的地址,由于被調(diào)函數(shù)在參數(shù)指針的作用域之內(nèi),此時直接改變變量的本體。
返回值: 計(jì)算結(jié)果表示函數(shù)執(zhí)行的順利與否(-1、0) 返回值可以為各種數(shù)據(jù)類型,如:int,float,double,char,a[數(shù)組],*a(指針),結(jié)構(gòu)或類。寫return是一種清晰的風(fēng)格,可以防止一些意外的錯誤。有時候也是想中斷函數(shù)執(zhí)行,返回調(diào)用函數(shù)處。
返回本地變量的地址是危險(xiǎn)的,返回全局變量或靜態(tài)本地變量的地址是安全的,返回在函數(shù)malloc的內(nèi)存是安全的,但是容易造成問題,最好的辦法是返回傳入的指針。
在函數(shù)中調(diào)用函數(shù)自己? :即自己return自己 = 遞歸
?
#include//輸出直到n項(xiàng)的斐波那契數(shù)列 int add(int n);int i; int main(void) { int n; scanf("%d", &n); int c; for (i = 1; i <=n; i++) {//輸出數(shù)列 c = add(i);//調(diào)用函數(shù) printf("%d ", c); } return 0; }int add(int n) {//遞歸 if (n == 1) {//第一位數(shù)是1 return 1; } else if (n == 2) {//第二位數(shù)也是1 return 1; } else { return (add(n-1) + add(n - 2));//第三位開始 等于它前兩位相加 1+1=2 所以第三位是2 } }
?
本地變量和全局變量的補(bǔ)充
本地變量的規(guī)則:
本地變量是定義在塊內(nèi)的:它可以是定義在函數(shù)的塊內(nèi),也可以是定義在語句的塊內(nèi),甚至可以隨便拉一對大括號來定義變量。
但是程序進(jìn)入這個塊之前,在這個塊內(nèi)定義的變量它是不存在的,離開這個塊,它也隨之消失。
所以,在塊外面定義的變量在變量仍然有效,然而在塊里邊定義的變量出去塊外邊就無效了。
注意 :如果在塊外邊定義和里邊同名的變量,里邊的變量會覆蓋外邊的值(小覆蓋大的)。
不能再同一個塊內(nèi)定義同名變量,本地變量不會被初始化,參數(shù)再進(jìn)入函數(shù)的時候就被初始化了。
本地變量的規(guī)則:
沒有做初始化的全局變量會得到零值,指針會得到NULL,只能用編譯時刻已知道的值來初始化全局變量,它們的初始化再main函數(shù)之前。
注意:盡量不要使用全局變量來在函數(shù)之間傳遞參數(shù)和結(jié)果。盡量避免使用全局變量(豐田的案子),使用全局變量和靜態(tài)的本地變量是線程不安全的。
審核編輯:湯梓紅
評論
查看更多