一、函式概述
1、首先什麼是函式?
函式是用於完成特定任務的程式**的自包含單元。
2、為什麼使用函式? 第
一、函式的使用可以身故重複**的編寫。第
二、函式使得程式更加模組化,有利於程式的閱讀修改和完善。
3、main函式原型
int main (int argc, char * argv, char * envp)
第乙個引數:命令列引數的個數
引數argc表示輸入引數的個數(含命令名),如果有命令列引數,argc應不小於1;argv表示傳入的引數的字串,是乙個字串陣列,argv[0]表示命令名,argv[1]指向第乙個命令列引數;
至於第三個引數env,它與全域性變數environ相比也沒有帶來更多益處,所以posix.1也規定應使用environ而不使用第三個引數。通常用getenv和putenv函式來訪問特定的環境變數,而不是直接使用environ變數。例如:
//main函式原型的使用
#include int main(int argc,char* argv,char* envp)
輸出結果:
tarena@ubuntu:~/project/c$ ./a.out i love you
the command line has 3 arguments:
1: i
2: love
3: you
每個c程式都必須有乙個 main 函式,因為它是程式執行的起點。關鍵字 int 表示函式返回乙個整型值,關鍵字 void 表示函式不接受任何引數。main 函式的函式體包括左花括號和與之匹配的右花括號之間的任何內容。
注意:如果沒有寫明返回值,一般預設為 int 型別。
main (void)
二、函式宣告和定義
1、函式宣告
在任何程式在使用函式之前都需要宣告該函式的型別。
例如:int imax (int a, int b);
第乙個int指的是函式型別;位於圓括號內的兩個int表明該函式的形式引數為int型別。分號的作用表示該語句是進行函式宣告而不是函式定義。
在函式原型中可以根據自己的喜好省略變數名。
int imax (int , int);
需要注意的是這些變數名只是虛設的名字,他們不必和函式定義中使用的變數名想匹配。使用這種函式原型資訊,編譯器就可以檢查函式呼叫語句是否和其原型宣告一致。比如檢查引數個數是否正確,引數型別是否匹配。將宣告語句放置在main ()之前和之內兩種方式都是正確的。需要重點注意的是函式宣告要在使用函式之前進行。當在main之前函式定義的話,就不需要宣告語句了。
#include int imin (int, int);
int main (void)
2、隱式宣告
如果被呼叫函式寫在呼叫函式後面則編譯器會猜測被呼叫函式的格式,這叫做函式的隱式宣告。隱式宣告可以和實際情況不一致這時就會出錯,可以把被呼叫函式的宣告單獨寫在檔案開頭,這叫做函式的顯示宣告。除了主函式以外的所有函式都應該進行顯示宣告,因為主函式永遠不是被呼叫函式。如果main()之後又函式定義,main()之前卻沒有函式宣告的話,編譯的時候會出現隱式宣告報錯。
3、標頭檔案的使用
如果把main ()函式放在第乙個檔案中吧自定義哈拿書放在第二個檔案中實現,那麼第乙個檔案仍需要使用函式原型。如果把函式原型放在乙個標頭檔案中,就不必每次使用這些函式時輸入其原型宣告了。
#ifndef __02read_h__
#define __02read_h__
extern int num; //主函式全域性變數寫在了標頭檔案裡且要加extern關鍵字
int read(char, int); //函式宣告
#define pi 3.14
#endif
4、函式定義
函式宣告只是將函式型別告訴編譯器,而函式定義部分則是函式的實際實現**。之所以使用函式原型,是為了在編譯器編譯第乙個呼叫函式的語句之前想其表明該函式的使用方法。因此,可以在首次呼叫某函式之前對該函授進行完整的定義。這樣函式定義部分就和函式原型有著相同的作用。通常對較小的函式會這樣做:
//下面既是乙個函式的定義,也是它的原型
#include int imax (int a, int b)
int main (void)
三、函式形參與實參
1、形式引數
函式定義為下面的函式:
void show (char ch, int num)
這行**通知編譯器show()使用名為ch和num的兩個引數,並且這兩個引數的型別分別為char和int。變數ch和num被稱為形式引數。
注意:ansi c形式要求在每個變數前宣告其型別。也就是說,不能像通常變數宣告那樣使用變數列表宣告同一型別的變數。如下所示:
void dibs (int x, y, z) /*不正確的函式頭*/
void dibs (int x, int y, int z) /*正確的函式頭*/
2、實際引數
函式呼叫中,通常使用實際引數對ch和num賦值,如:
show (space, 12);
形式引數是被調函式中的變數,而實際引數是呼叫函式分配給被呼叫函式變數的特定數值。實際引數可以是常量、變數或乙個複雜的表示式。但是無論何種形式的實際引數,執行時首先要計算其值,然後將該值複製給被呼叫函式中相應的形式引數。
3、無引數
void dibs (void);
為了表示乙個函式確實不使用引數,需要在圓括號內加入void關鍵字。
四、遞迴函式
1、遞迴介紹
c允許乙個函式條用其本身,這種呼叫過程被稱為遞迴。
遞迴與迴圈比較:
採用遞迴函式解決問題的思路叫遞迴
採用迴圈解決同樣問題的思路叫遞推
遞迴一般可以代替迴圈語句使用。有些情況下使用迴圈語句比較好,而有些時候使用遞迴更有效。遞迴方法雖然使用程式結構優美,但其執行效率卻沒有迴圈語句高。一般來說,選擇迴圈更好一些。首先,因為每次遞迴呼叫都擁有自己的變數集合,所以就需要占用較多的記憶體;每次遞迴呼叫需要把心的變數集合儲存在堆疊中。其次,由於進行每次函式呼叫需要花費一定的時間,所以遞迴的執行速度較慢。
//示例一
#include void show (int);
int main (void)
void show (int n)
執行結果如下:
level 1: n location 0xbf8bf680
level 2: n location 0xbf8bf660
level 3: n location 0xbf8bf640
level 4: n location 0xbf8bf620
level 4: n location 0xbf8bf620
level 3: n location 0xbf8bf640
level 2: n location 0xbf8bf660
level 1: n location 0xbf8bf680
//示例二
#include void print (int num)
printf ("%d\n", num);
print (num -1);
}int main (void)
輸出結果:109
8765
4321
2、遞迴的基本原理
第一:每一級的函式呼叫都有自己的變數。
第二:每一次函式呼叫都會有一次返回。
第三:遞迴函式中,位於遞迴呼叫前的語句和各級被呼叫函式具有相同的執行順序。
第四:遞迴函式中,位於遞迴呼叫後的語句的執行順序和各個被呼叫函式的順序相反。
第五:雖然每一級遞迴都有自己的變數,但是函式**並不會得到複製。
最後:遞迴函式中必須包含可以終止遞迴呼叫的語句。
3、遞迴的優缺點
其優點在於為某些變成問題提供了最簡單的解決方法,而缺點是一些遞迴演算法會很快耗盡計算機的記憶體資源。同時,使用遞迴的程式難於閱讀和維護。
五、指標函式和函式指標
指標函式:返回指向char的指標的函式,例如:char * fump ( );
函式指標:指向返回型別char的函式指標,例如:char (* frump) ( );
這裡需要明白乙個符號之間優先順序的問題,"( )"的優先順序比"*"要高。
再考慮乙個,char (* flump[3]) ( );
由3個指標組成的陣列,每個指標指向返回型別為 char 的函式。
c語言 再學習筆記
簡單的來說 在區域性變數前加上 static 可以延長他的生命週期 由 函式呼叫時 延長至 程式存活週期 在全域性變數前加上static 可以減小它的作用域 由 多檔案可見,減小到單檔案內 可見 局變數的說明之前再加以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性...
c語言再學習之巨集與函式
巨集概念 c 巨集定義將乙個 識別符號定義為乙個字串,源程式 中的該識別符號均以指定的字串來代替。巨集書寫形式 define 巨集名 參數列 巨集體 巨集與函式的區別 時間上考慮 1 巨集只佔編譯時間,函式呼叫則占用執行時間 分配單元,儲存現場,值傳遞,返回 每次執行都要載入,所以執行相對巨集會較慢...
c 再學習(內聯函式)
什麼是內聯函式?以inline修飾的函式叫做內聯函式,編譯時c 編譯器會在呼叫內聯函式的地方展開,沒有函式壓棧的開銷,內聯函式提公升程式執行的效率。內聯函式與普通函式執行過程有何不同?普通函式的執行過程中,首先要儲存暫存器的位置,然後傳入引數 這時程式轉到函式處執行,然後再返回,而內聯函式不需要這麼...