C 語言程序設計---函數

一篇入門級別的C語言函數,值得一看。

圖片發(fā)自簡書App

上次寫了 C 語言入門級別的指針,這篇寫函數,指針和函數在一起使用,更有意思,這也才能最大程度的發(fā)揮指針的作用。


基本概念


C 語言是一個函數語言,函數相當于”工廠“,具有”來料加工“的能力。

1sqrt(2.0);

2//sqrt()函數,接收 2.0 這個來料,并把它加工成 1.414...這樣的結果。


1、

函數的分類

A、按 main() 和其它函數:主函數、其它函數

B、按作者分:系統(tǒng)函數(庫函數)、用戶自定義函數(我們自己寫的);無論是庫函數,還是用戶自定義函數,其產生過程和調用,都應遵循相同的編程原則;

C、按函數調用關系分:主調函數、被調函數;

D、函數按參數個數劃分:定參函數、不定參函數。


定參函數,參數個數固定;不定參函數,參數個數不確定;定參函數又分為有參函數和無參函數。

1printf("%d%d%d", a, b, c);? //4 個參數

2printf("Hello\n");? //1 個參數

3//所以 printf() 是一個不定參函數

4//若函數無參,則可以用 void 加以明確聲明

5void main(void){}? //名稱為 main 的函數,無返回值,無參數


2、

函數的產生和使用過程(步驟)


A、函數聲明

B、函數定義

C、函數調用


函數聲明:

(1)、確定的函數名稱,函數名稱是用以區(qū)分其它函數的標志,是這個函數的”入口“地址常量。

(2)、說明函數的返回值類型,sqrt(2.0) 的計算結果為 1.414,這個 1.414 就是所謂的返回值;

函數可以沒有返回值,此時該函數返回值類型必須明確的寫成:void;

返回值是由被調函數返回給主調函數的數值;函數若有返回值,最多只能有一個返回值;

(3)、說明函數的參數,參數個數以及每個參數的數據類型;函數在聲明時,可以只說明參數類型,而缺省相關變量。

1int fun(int n);

2int fun(int);

//以上函數聲明都是正確的


函數定義:

就是函數的編程,實現函數的功能,主要包含函數首部和函數體。

函數首部包括:函數返回值類型、函數名稱、以及形參;

函數體是由 {} 括起來的語句組成。

1int fun(int m){}


注意:

(1)、若函數明確聲明不是 void,則該函數必須以 {return 表達式;} 語句結束,并且,表達式類型必須與函數的返回值類型完全一致!

若函數返回值為 void,則可以寫 return; 語句結束,也可以缺省這條語句。

特別強調:return (表達式); 這樣的寫法,在概念上是一種壞習慣,在 C 語言中,xxx() 出現,代表的是對 xxx() 函數的調用,上面的寫法好像就是在說 return 是函數名稱,而實際上,return 是關鍵字!


(2)、關于 return

A、它是函數運行結束的語句,在這條語句后出現的任何其它語句,是絕對不會運行到的。

1if (條件) {

2? ? return ;

3}

4語句1;

5//明顯,只有條件不成立,才能執(zhí)行語句1

6}


B、所謂的函數運行結束的 return(返回),是“返回”到調用它的函數的下一條語句繼續(xù)執(zhí)行。

C、所謂的 return 表達式; 意思是,返回到主調函數,并用“表達式”的值,替代主調函數中,關于這個函數的調用部分內容。


函數調用:

1#include <stdio.h>

2

3int add (int a, int b);? //函數聲明

4int add (int a, int b) {? //函數定義

5? ? return a + b;

6}

7int main (void) {

8? ? int a;

9? ? int b;

10? ? int sum;

11

12? ? scanf("%d%d", &a, &b);

13? ? sum = add(a, b);? //函數調用

14

15? ? return 0;

16}


形參與實參


1、

形參與實參的定義

A、形參出現在函數定義的“函數首部”的括號中;

B、實參出現在函數調用的括號中;

C、實參有三種形式:常量、變量、表達式;

D、形參只有一種形式:變量。

1int fun (int num);

2int fun (int num) {? //這個 num 就是形參? 這塊是函數定義

3? ...

4}

5

6int main (void) {

7? ? int a;

8

9? ? a = fun(5);? //這個 5 就是實參? 這塊是函數調用

10}


形參只有變量這一種形式,不可能出現常量,甚至不可能出現數組!


2、

(1)、形參與實參之間的關系

A、個數一致;

B、按位置關系必須對應;

C、數據類型必須一致;

D、值傳遞


將實參表達式的值,復制一份,賦值給形參變量!


(2)、私有變量

在一個函數的函數體中定義的變量,以及該函數的所有形參變量,都是這個函數的私有變量。

一個函數只能使用、調用這個函數的私有變量和“公有變量”,絕對不能直接使用其它函數的私有變量(包括數組)。

私有變量是在定義這個變量的函數被調用時,才申請存儲空間;私有變量(尤其是形參變量)的空間,與其它函數的私有變量的空間,是沒有任何關系的,即,其空間是獨立申請的。

私有變量將隨著定義它的函數的運行結束,而釋放其空間。


(3)、形參不能修改實參的值

被調函數對形參變量所進行的任何修改,絕對不會更改與其對應的實參的值,這就是“值傳遞”的必然結果?。?!

對形參變量所進行的任何修改,絕對不會更改實參表達式的值 !

C 語言中,“指針”存在的理由:

最核心的原因:C 語言是一個函數語言,沒有過程這個概念,就需要指針傳變量的地址,才能對變量進行修改!


函數特點


1、

C 語言函數的重要特點

A、高度的獨立性:任何函數只能引用屬于自己的私有變量和全局變量,絕對不能直接引用其它函數的私有變量;這意味著,不能在被調函數中,直接修改主調函數的私有變量的值;

B、函數返回值最多只有一個,若需要通過被調函數同時得到多個結果,那是行不通的;

C、函數的參數(實參與形參)的關系,在 C 語言函數中,只有一種:值傳遞(傳遞的是值,只不過這個值可能是普通的值,也可能是地址值),且這種傳遞方式所產生的必然結果是:對被調函數的形參變量所進行的任何更改,絕對不會影響主調函數的實參的值!

上述三個特點,將對 C 語言函數的功能產生巨大的束縛:在上述情況存在的前提下,C 函數是無法實現:“同時更改主調函數中多個私有變量的值”的功能!


2、

指針的概念,就是為了解決上述 C 語言“致命”問題而提出來的!

指針解決上述問題的具體方法:

A、將需要更改的變量(空間)的首地址作為實參;

B、被調函數對應的形參變量必須是上述變量的指針類型進行接收,這將使被調函數的形參變量“指向”主調函數中,需要更改的那個變量;

C、在被調函數中,通過 * (指向)運算,間接地修改主調函數相關變量的值。

1void fun (int *);

2void fun (int *num) {

3? ? *num = 5;? //通過指針修改 a 空間的值,進行了指向運算

4}

5

6int main (void) {

7? ? int a = 6;

8

9? ? fun(&a);? //傳的是 a 空間的地址

10? ? printf("%d\n", a)? //輸出的結果是 5

11}


變量生命域與作用域


1、

全局變量與局部變量

(1)、全局變量的定義是在 {} 之外進行的;在 {} 之內定義的變量和所有的形參變量都是局部變量;

(2)、全局變量能被那些在書寫順序上,其后定義的函數所引用;局部變量只能被定義它的函數所引用;

(3)、全局變量的空間是在主函數運行之前申請的,且在主函數運行結束后(即,整個程序運行完畢后)才釋放空間的;局部變量是在定義它的函數被調用時才申請空間,且隨著函數運行結束而釋放空間;

(4)、全局變量在定義后賦值前,其值由 C 語言強制賦值為 0;局部變量在定義后賦值前,其值為垃圾;

(5)、全局變量的使用,可使程序設計變得方便,但這種方便會帶來函數之間“耦合”程度的增加,不利于大中型軟件開發(fā),不利于團隊開發(fā),也不利于軟件的維護;全局變量的使用必須謹慎,這是《軟件工程》思想所推薦的。


2、

變量存儲類型

自動存儲類:auto (可缺?。﹊nt a; <=> auto signed int

靜態(tài)存儲類:static

寄存器存儲類:register

外部存儲類:extern


(1)、自動存儲類變量和靜態(tài)存儲類變量的定義:

1int a;

2static int b;

(2)、靜態(tài)存儲類變量是在主函數運行前申請空間,且在整個程序運行結束后釋放;自動存儲類變量是在定義它的函數被調用時才申請空間,且在定義它的函數運行結束后,釋放其空間;

(3)、靜態(tài)存儲類變量在定義后未賦值前,其值被 C 語言強行賦值為 0;自動存儲類變量在定義后未賦值前,其值為垃圾值;

(4)、靜態(tài)存儲類變量,如果是局部變量,則只能被定義它的函數所引用;

(5)、若某函數被多次調用,且該函數定義有靜態(tài)存儲類變量;則,在調用該函數結束后,它所定義的自動存儲類變量的空間都被釋放,而靜態(tài)存儲類變量的空間是不釋放的;在下一次該函數被調用時,靜態(tài)存儲類空間的值是在上一次調用結束的基礎上進行再一次引用的,因此,靜態(tài)存儲類變量具有“累加”效應。


函數遺留問題


一維數組名稱作為實參、二維數組名稱作為實參,形參該以何種數據類型接收的呢?又怎么使用呢?

函數的遞歸調用,也就是常見的遞歸算法有哪些條件呢?遞歸又該如何實現?有哪些應該的場景需要遞歸呢?

在操作系統(tǒng)底層源碼中好多寫法就是函數指針,指向函數的指針,那么指針函數和函數指針又該怎么理解呢?怎么使用呢?

針對這些遺留問題,有興趣的可以自己先去思考、去學習,去研究,我在寫 C 進階之旅的時候,都會寫到。

本篇文章僅僅是把 C 語言的函數帶入門,以及說明了為什么要有指針,指針的出現就是為了函數中的傳參,學習 C 語言之旅,路還很長,琢磨透徹,在敲代碼實現,總會有進步的!

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 指針是C語言中廣泛使用的一種數據類型。 運用指針編程是C語言最主要的風格之一。利用指針變量可以表示各種數據結構; ...
    朱森閱讀 3,606評論 3 44
  • 在C語言中,五種基本數據類型存儲空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 3,999評論 0 2
  • 1.C和C++的區(qū)別?C++的特性?面向對象編程的好處? 答:c++在c的基礎上增添類,C是一個結構化語言,它的重...
    杰倫哎呦哎呦閱讀 9,985評論 0 45
  • 1.語言中變量的實質 要理解C指針,我認為一定要理解C中“變量”的存儲實質, 所以我就從“變量”這個東西開始講起吧...
    金巴多閱讀 1,972評論 0 9
  • 原文地址:C語言函數調用棧(一)C語言函數調用棧(二) 0 引言 程序的執(zhí)行過程可看作連續(xù)的函數調用。當一個函數執(zhí)...
    小豬啊嗚閱讀 4,957評論 1 19

友情鏈接更多精彩內容