天天看點

C語言基礎 — ( 函數——子產品化設計)前言一、怎樣定義函數二、定義函數的方法三、調用函數四、對被調用函數的聲明和函數原型五、函數的嵌套調用六、總結

歡迎小夥伴的點評✨✨ 本篇章系列是對C語言的深度思考和總結、關于C語言内容會持續更新

文章目錄

  • 前言
  • 一、怎樣定義函數
  • 二、定義函數的方法
    • 2.1、定義無參函數
    • 2.2、定義有參函數
    • 2.3、定義空函數
  • 三、調用函數
    • 3.1、函數調用的形式
    • 3.2、函數調用時的資料傳遞
    • 3.3、函數調用的過程
    • 3.4、函數的傳回值
  • 四、對被調用函數的聲明和函數原型
  • 五、函數的嵌套調用
    • 5.1、函數的遞歸調用
  • 六、總結

前言

“函數”是從英文 function 翻譯過來的,其實,function在英文中的意思是“函數”,也是“功能”。從本質意義上來說,函數就是用來完成一定的功能的。這樣,對函數的概念就很好了解了,所謂函數名就是給該功能起一個名字,如果該功能是用來實作求正弦運算的,就稱為正弦函數。

注意: 函數就是功能。每一個函數用來實作一個特定的功能。函數的名字應反映其代表的功能。

在設計一個較大的程式時,往往把它分為若幹個程式子產品,每一個子產品包括一個或多個函數,每個函數實作一個特定的功能。一個C程式可由一個主函數和若幹個其他函數構成。由主函數調用其他函數,其他函數也可以互相調用。同一個函數可以被一個或多個函數調用任意多次。

說明:

(1) 一個C程式由一個或多個程式子產品組成,每一個程式子產品作為一個源程式檔案。對較大的程式,一般不希望把所有的内容全放在一個檔案中,而是将它們分别放在若幹個源檔案中,由若幹個源程式檔案組成一個C程式。這樣便于分别編寫和編譯,提高調試效率。一個源程式檔案可以為多個C程式共用。

(2)一個源程式檔案由一個或多個函數以及其他有關内容(如指令、資料聲明與定義等)組成。一個源程式檔案是一個編譯機關,在程式編譯時是以源程式檔案為機關進行編譯的,而不是以函數為機關進行編譯的。

(3)C程式的執行是從main函數開始的,如果在main函數中調用其他函數,在調用後流程傳回到main函數,在main函數中結束整個程式的運作。

(4)所有函數都是平行的,即在定義函數時,是分别進行的,是互相獨立的。一個函數并不從屬于另一個函數,即函數不能嵌套定義。函數間可以互相調用,但不能調用main函數。main函數是被作業系統調用的。

(5)從使用者使用的角度看,函數有兩種。

①庫函數,它是由系統提供的,使用者不必自己定義,可直接使用它們。應該說明,不同的C語言編譯系統提供的庫函數的數量和功能會有一些不同,當然許多基本的函數是共同的。

②使用者自己定義的函數。它是用以解決使用者專門需要的函數。

(6) 從函數的形式看,函數分兩類。

① 無參函數。在調用無參函數時,主調函數不向被調用函數傳遞資料。無參函數一般用來執行指定的一組操作。無參函數可以帶回或不帶回函數值,但一般以不帶回函數值的居多。

②有參函數。在調用函數時,主調函數在調用被調用函數時,通過參數向被調用函數傳遞資料,一般情況下,執行被調用函數時會得到一個函數值,供主調用函數使用。此時有參函數應定義為與傳回值相同的類型。

一、怎樣定義函數

C語言要求,在程式中用到的所有函數,必須“先定義,後使用”。

定義函數應包括以下幾個内容:

(1) 指定函數的名字,以便以後按名調用。

(2) 指定函數的類型,即函數傳回值的類型。

(3) 指定函數的參數的名字和類型,以便在調用函數時向它們傳遞資料。對無參函數不需要這項。

(4) 指定函數應當完成什麼操作,也就是函數是做什麼的,即函數的功能。這是最重要的,是在函數體中解決的。

對于C編譯系統提供的庫函數,是由編譯系統事先定義好的,庫檔案中包括了對各函數的定義。程式設計者不必自己定義,隻須用#include指令把有關的頭檔案包含到本子產品中即可。

庫函數隻提供了最基本,最通用的一些函數,而不可能包括人們在實際應用中所用到的所有函數。程式設計者需要在程式中自己定義想用的而庫函數并沒有提供的函數。

二、定義函數的方法

2.1、定義無參函數

定義無參函數的一般形式為

類型名 函數名()

{

函數體

}

類型名 函數名(void)

{

函數體

}

函數名後面括号内的 void 表示“空”,即函數沒有參數。

函數體包括 聲明部分 和 語句部分 。

在定義函數時要用 類型辨別符 (即類型名)指定函數值的類型,即指定函數帶回來的值的類型。

2.2、定義有參函數

定義有參函數的一般形式為

類型名 函數名(形式參數表列)

{

函數體

}

函數體包括聲明部分和語句部分。

2.3、定義空函數

在程式設計中有時會用到空函數,它的形式為

類型名 函數名()

{ }

函數體是空的。調用此函數時,什麼工作也不做,沒有任何實際作用。

在程式設計中往往根據需要确定若幹個子產品,分别由一些函數來實作。而在第1個階段隻設計最基本的子產品,其他一些次要功能或錦上添花的功能則在以後需要時陸續補上。在編寫程式的開始階段,可以在将來準備擴充功能的地方寫一個空函數(函數名取将來采用的實際函數名),隻是這些函數暫時還未編好,先用空函數占一個位置,等以後擴充程式功能時用一個編好的函數代替它。這樣做,程式的結構清楚,可讀性好,以後擴充新功能友善,對程式結構影響不大。空函數在程式設計中常常是有作用的。

三、調用函數

定義函數的目的是為了調用此函數,以得到預期的結果。是以,應當熟練掌握調用函數的方法和有關概念

3.1、函數調用的形式

調用一個函數的方法很簡單,如前面已見過的:

函數調用的一般形式為

函數名(實參表列)

如果是調用無參函數,則 實參表列 可以沒有,但括号不能省略。如果實參表列包含多個實參,則各參數間用逗号隔開。

按函數調用在程式中出現的形式和位置來分,可以有以下3種函數調用方式。

  1. 函數調用語句

    把函數調用單獨作為一個語句。如 printf(“Hello World !\n”); ,這時不要求函數帶回值,隻要求函數完成一定的操作。

  2. 函數表達式

    函數調用出現在另一個表達式中,如“c=max(a,b);” ,max(a,b)是一次函數調用,它是指派表達式中的一部分。這時要求函數帶回一個确定的值以參加表達式的運算。

  3. 函數參數

    函數調用作為另一個函數調用時的實參。例如:

    m=max(a,max(b,c));

    其中,max(b,c)是一次函數調用,它的值是b和c二者中的 大者 ,把它作為max另一次調用的實參。經過指派後,m的值是a,b,c

    三者中的最大者。

    說明: 調用函數并不一定要求包括分号,隻有作為函數調用語句才需要有分号。如果作為函數表達式或函數參數,函數調用本身是不必有分号的。

3.2、函數調用時的資料傳遞

  1. 形式參數和實際參數

    在調用 有參函數 時,主調函數和被調用函數之間有資料傳遞關系。從前面已知:在定義函數時函數名後面括号中的變量名稱為

    形式參數(簡稱 形參 )或 虛拟參數 。在主調函數中調用一個函數時,函數名後面括号中的參數稱為 實際參數(簡稱 實參 )。實際參數可以是常量、變量或表達式。

  2. 實參和形參間的資料傳遞

    在調用函數過程中,系統會把實參的值傳遞給被調用函數的形參。或者說,形參從實參得到一個值。該值在函數調用期間有效,可以參加該函數中的運算。

    在調用函數過程中發生的實參與形參間的資料傳遞稱為 虛實結合 。

    說明:

    (1) 實參可以是常量,變量或表達式,例如:max(3,a+b),但要求它們有确定的值。在調用時将實參的值賦給形參。

    (2) 實參與形參的類型應相同或指派相容。

3.3、函數調用的過程

(1) 在定義函數中指定的形參,在未出現函數調用時,它們并不占記憶體中的存儲單元。在發生函數調用時,函數的形參才被臨時配置設定記憶體單元。

(2) 将實參的值傳遞給對應形參。

(3) 在執行函數期間,由于形參已經有值,就可以利用形參進行有關的運算。

(4) 通過 return 語句将函數值帶回到主調函數。

(5) 調用結束,形參單元被釋放。

3.4、函數的傳回值

通常,希望通過函數調用使主調函數能得到一個确定的值,這就是函數值(函數的傳回值)

下面對函數值作一些說明。

(1) 函數的傳回值是通過函數中的return 語句獲得的。return 語句将被調用函數中的一個确定值帶回到主調函數中去。如果需要從被調用函數帶回一個函數值(供主調函數使用),被調用函數中必須包含return 語句。如果不需要從被調用函數帶回函數值可以不要return 語句。

一個函數中可以有一個以上的return 語句,執行到那一個return 語句,那一個return 語句就起作用。return 語句後面的括号可以不要,如 return z; 與 return(z); 等價。 return 後面的值可以是一個表達式。

(2) 函數值的類型。既然函數有傳回值,這個值當然應屬于某一個 确定的類型,應當在定義函數時指定函數值的類型。

(3) 在定義函數時指定的函數類型一般應該和return 語句中的表達式類型一緻。如果函數值的類型和return語句中表達式的值不一緻,則以函數類型為準。對數值型資料,可以自動進行類型轉換。即函數類型決定傳回值的類型。

(4) 對于不帶傳回值的函數,應當用定義函數為 void 類型 (或稱 空類型 ) 。這樣,系統就保證不使函數帶回任何值,即禁止在調用函數中使用被調用函數的傳回值。此時在函數體中不得出現return 語句。

四、對被調用函數的聲明和函數原型

在一個函數中調用另一個函數(即被調用函數)需要具備如下條件:

(1) 首先被調用的函數必須是已經定義的函數(是庫函數或使用者自己定義的函數)。但僅有這一條件還不夠。

(2) 如果使用庫函數,應該在本檔案開頭用#include 指令将調用有關庫函數時所需用到的資訊 包含 到本檔案中來。

(3) 如果使用使用者自己定義的函數,而該函數的位置在調用它的函數(即主調函數)的後面(在同一個檔案中),應該在主調函數中對被調用函數作 聲明 (declaration) 。聲明的作用是把函數名,函數參數的個數和參數類型等資訊通知編譯系統,以便在遇到函數調用時,編譯系統能正确識别函數并檢查調用是否合法。

函數的聲明和函數的定義中的函數首部基本上是相同的,隻差一個分号(函數聲明比函數定義中的首行多一個分号)。是以寫函數聲明是,可以簡單地照寫已定義的函數的首行,再加一個分号,就成了 聲明 。函數的首行 (即函數首部) 稱為 函數原型 。為什麼要用函數的首部來作為函數聲明呢? 這是為了便于對函數調用的合法性進行檢查。因為在函數的首部包含了檢查調用函數是否合法的基本資訊(它包括了函數名,函數值類型,參數個數,參數類型和參數順序),在檢查函數調用時要求函數名,函數類型,參數個數和參數順序必須與函數聲明一緻,實參類型必須與函數聲明中的形參類型相同(或指派相容,如實型資料可以傳遞給整型形參,按指派規則進行類型轉換)否則就按錯處理。這樣就能保證函數的正确調用。

說明: 使用函數原型作聲明是C的一個重要特點。用函數原型來聲明函數,能減少編寫程式時可能出現的錯誤。由于函數聲明的位置與函數調用語句的位置比較近,是以在寫程式時便于就近參照函數原型來書寫函數調用,不易出錯。

實際上,在函數聲明中的形參名可以省寫,而隻寫形參的類型,如上面的聲明可以寫為

float add(float ,float ); //不寫參數名,隻寫參數類型

編譯系統隻關心和檢查參數個數和參數類型,而不檢查參數名,因為在調用函數時隻要求保證明參類型與形參類型一緻,而不必考慮形參名是什麼。是以在函數聲明中,形參名可寫可不寫,形參名是什麼都無所謂,如:

float add(float a,float b); //參數名不用x,y,而用 a,b 。合法

根據以上的介紹,函數聲明的一般形式有兩種,分别為

(1) 函數類型 函數名 (參數類型 1 參數名1 ,參數類型 2 參數名2 , … ,參數類型 n 參數名n )

(2) 函數類型 函數名 (參數類型 1 , 參數類型 2 , … ,參數類型 n 參數名n )

注意: 對函數的 定義 和 聲明 不是同一回事。函數的定義是指對函數功能的确立,包括指定函數名、函數值類型、形參及其類型以及函數體等,它是一個完整的、獨立的函數機關。而函數的聲明的作用則是把函數的名字、函數類型以及形參的類型、個數和順序通知編譯系統,以便在調用該函數時系統按此進行對照檢查(例如,函數名是否正确,實參與形參的類型和個數是否一緻),它不包含函數體。

如果已在檔案的開頭(在所有函數之前),已對本檔案中所調用的函數進行了聲明,則在各函數中不必對其所調用的函數再作聲明。

由于在檔案的開頭(再函數的外部)已對要調用的函數進行了聲明(這些稱為 外部的聲明 ),是以在程式編譯時,編譯系統已從外部聲明中知道了函數的有關資訊,是以不必再主調函數中重複進行聲明。寫在所有函數前面的外部聲明在整個檔案範圍有效。

五、函數的嵌套調用

C語言的函數定義是互相平行、獨立的,也就是說,在定義函數時,一個函數内不能再定義另一個函數,即不能嵌套定義,但可以嵌套調用函數,即在調用一個函數的過程中,有調用另一個函數。

5.1、函數的遞歸調用

在調用一個函數的過程中又出現 直接或間接地調用該函數本身,稱為函數的遞歸調用 。C語言的特點之一就在于允許函數的遞歸調用。

六、總結

當程式的功能比較多,規模比較大,把所有的程式代碼都寫在一個主函數(main 函數)中,就會使主函數變得龐雜、頭緒不清,使閱讀和維護程式變得困難。此外,有時程式中要多次實作某一功能(例如列印每一頁的頁頭),就需要多次重複編寫實作此功能的程式代碼,這使程式冗長、不精煉。

是以,人們自然會想到采用 組裝 的辦法來簡化程式設計的過程。如同組裝計算機一樣,事先生産好各種部件(如電源、主機闆、CD光牒驅動器、風扇等),在最後組裝計算機時,用到什麼就從倉庫裡取出什麼,直接裝上就可以了。絕不會采用手工業方式,在用到電源時臨時生産一個電源,用到主機闆時臨時生産一個主機闆。這就是 子產品化程式設計 的思路。

繼續閱讀