C語言--函數


原有的編程實例已經獨立為一篇博客!


函數的定義

函數是一個完成特定工作的獨立程序模塊,包括庫函數和自定義函數兩種。例如,scanf()、printf()等為庫函數,由C語言系統提供定義,編程時只要直接調用即可;而有時,我們需要一些能實現特定功能的函數,這時就需要用戶自己定義,屬於自定義函數。從函數實現計算功能角度來看,C語言的函數與數學上的函數概念十分接近。在C程序中必然為某一種數據類型,稱其為函數類型。
函數定義的一般形式為:

函數類型 函數名(形式參數表)   /*函數首部*/
{
函數實現過程   /*函數體*/
}

函數首部

函數首部由函數類型、函數名和形式參數表(以下簡稱形參表)組成,位於函數義的第一行。函數首部中,函數名是函數整體的稱謂,需用一個合法的標識符表示。函數類型指函數結果返回的類型,一般與return語句中表達式的類型一致。形參表中給出函數計算所要用到的相關已知條件,以類似變量定義的形式給出,其格式為:
類型形參1,類型2 形參2,…,類型n形參n
 形參表中各個形參之間用逗號分隔,每個形參前面的類型必須分別寫明。函數的 參的數量可以是一個,也可以是多個,或者沒有形參。

  • 函數首部后面不能加分號,它和函數體一起構成完整的函數定義。

函數體

函數體體現函數的實現過程,由一對大括號內的若干條語句組成,用於計算,或完成特定的工作,並用return語句返回運算的結果。

函數的調用

定義一個函數后,就可以在程序中調用這個函數。在C語言中,調用標准庫函數時.只需要在程序的最前面用include命令包含相應的頭文件;調用自定義函數時,程序中必須有與調用函數相對應的函數定義。作為初學者的我們,充分理解函數調用與返回的實現過程,對學好函數程序設計是至關重要的。

函數調用過程

任何C程序執行,首先從主函數main()開始,如果遇到某個函數調用,主函數將被暫停執行,轉而執行相應的函數,該函數執行完后將返回主函數,然后再從原先暫停的位置繼續執行。

函數調用的形式

函數調用的一般格式為:

函數名(實際參數表)

實際參數(簡稱實參)可以是常量、變量和表達式作為實參,對於實現計算功能的函數,函數調用通常出現在賦值語句或輸出函數的實參。

參數傳遞

函數定義時,位於其首部的參數被稱為形參,主調函數的參數被稱為實參。形參除了能接受實參的值外,使用方法與普通變量類似。形參和實參必須一一對應,兩者數量相同,類型盡量一致。程序運行遇到函數調用時,實參的值依次傳給形參,這就是參數傳遞。
函數的形參必須是變量,用於接受實參傳遞過來的值;而實參或表達式其作用是把常量變量或表達式的值傳遞給形參。如果實參是變量,它與所對應的形參是兩個不同的變量。實參是主調函數的,形參是自定義函數的,這兩者可以同名,也可不同名。
按照C語言的規定,在參數傳遞過程中,將實參的值復制給形參。這種參數傳遞是單向的,只允許實參把值復制給形參,形參的值即使在函數中改變了,也不會反過來影響實參。

  • 實參和形參一一對應,數量應相同,順序應一致,初學時建議類型也保持一致。

函數結果返回

函數結果返回的形式如下:

return表達式;

先求解表達式的值,再返回其值。一般情況下表達式的類型與函數類型應一致,如果兩者不一致,以函數類型為准。return語句的作用有兩個:一是結束函數的運行;二是帶着運算結果(表達式的值)返回主調函數。
在函數體中,return語句中的表達式反映了函數運算的結果,通過return語句將該結果回送給主調函數。但return語句只能返回一個值,如果函數產生了多個運算結果,將無法通過return返回。例如求一元二次方程的函數,就不能用return返回兩個根。
在接下來的學習中,我們將會學習使用全局變量或指針實現函數多個結果返回。

  • return語句只能返回一個值。

函數原型聲明

C語言要求函數先定義后調用,就像變量先定義后使用一樣。如果自定義函數被放在主調函數的后面,就需要在函數調用前,加上函數原型聲明(或稱為函數聲明)。函數聲明的目的主要是說明函數的類型和參數的情況,以保證程序編譯時能判斷對該函數的調用是否正確。函數聲明的一般格式為:

函數類型 函數名(參數表);

即與函數定義中的第一行函數首部相同,並以分號結束。

  • 函數聲明是一條C語句,而函數定義時的函數首部不是語句,后面不能跟分號。

雖然可以將主調函數放在被調函數的后面,從而不需做聲明。但考慮到函數的執行順序,在編程時一般都把主函數寫在最前面,使整個程序的結構和功能開門見山地呈現在讀者面前,然后通過函數聲明解決函數先調用后定義的矛盾。

  • 如果在調用函數前,既不定義,也不聲明,程序編譯時會出錯。

不返回結果的函數

前面我們談的的函數主要是是起計算或判斷作用,最終有一個函數結果返回。在很多程序設計中,調用函數不是為了得到某個運算結果,而是要讓它產生某些作用,具有類似作用的函數在有些語言中也稱為過程。不返回結果的函數定義:

void函數名 (形參表)  /*函數首部*/
{
   函數實現過程   /*函數體*/
}

函數類型為void,表示不返回結果,函數體中可以使用沒有表達式的return語句,可以省略間return。void類型的函數雖然不直接返回一個值,但它的作用通常以屏幕輸出等方式體現。

  • 在不返回結果的函數定義中,void不能省略;否則,函數類型被默認定義為int。

省略了return語句,並不意味着函數不能返回。對於void類型的函數,如果省略了return語句,當函數中所有語句都執行完后,遇到最后的大括號即自動返回主調函數。
由於函數沒有返回結果,函數調用不可能出現在表達式中,通常以獨立的調用語句。
不返回結果的函數在定義、調用、參數傳遞、函數聲明上,思路完全與以前相同,只是函數類型變為void。它適用的場合主要是把一些確定的、相對獨立的程序功能封裝成函數。主函數通過調用不同的函數,體現算法步驟,而各步驟的實現由相應函數完成,從而簡化主函數結構,以體現結構化程序設計思想。

局部變量和全局變量

局部變量

迄今為止,在程序中使用的變量都定義在函數內部,它們的有效使用范圍被局限於所在的函數內。因此主調函數只有通過參數傳遞,才能把實參數據傳遞給函數使;同樣,形參的改變也不會影響到實參變量。這種變量的有效使用范圍,最大程度保了各函數之間的獨立性,避免函數之間相互干擾。
C語言中把定義在函數內部的變量稱為局部變量,局部變量的有效作用范圍局限於所在的函數內部。形參是局部變量。
使用局部變量可以避免各個函數之間的變量相互干擾。當函數使用了同名的形參時,甚至於主函數的實參變量也同名時,由於分屬不同函數,它們有各自不同的變量實體和使用范圍,不會相互千擾。C語言的這個特性在結構化程序設計中非常有用。
除了作用於函數的局部變量外,C語言還允許定義作用於復合語句中的局部變量,其有效使用范圍被局限於復合語句內,一般用作小范圍內的臨時變量。

  • 局部變量一般定義在函數或復合語句的開始處,標准C規定其不能定義在中間位置。

全局變量

局部變量雖然保證了函數的獨立性,但程序設計有時還要考慮不同函數之間的數據交流,及各函數的某些統一設置。當一些變量需要被多個函數共同使用時,參數傳遞雖然是一個辦法,但必須通過函數調用才能實現,並且函數只能返回一個結果,這會使程序設計受到很大的限制。為了解決多個函數間的變量共用,C語言允許定義全局變量。
定義在函數外而不屬於任何函數的變量稱為全局變量。全局變量的作用范圍是從定義開始到程序所在文件的結束,它對作用范圍內所有的函數都起作用。
全局變量的定義格式與局部變量完全一致,只是定義位置不在函數內,它可以定義在程序的頭部,也可以定義在兩個函數的中間或程序尾部,只要在函數外部即可。

  • 一般情況下把全局變量定義在程序的最前面,即第一個函數的前面。

由於全局變量和局部變量的作用范圍不同,允許它們同名。當某函數的局部變量與全局變量同名時,在該函數中全局變量不起作用,而由局部變量起作用。對於其他不存在同名變量的函數,全局變量仍然有效。同樣,當函數局部變量與復合語句的局部變量同名時,以復合語句為准。

  • 全局變量可以幫助解決函數多結果返回的問題,但全局變量更多地用於多函數間的全局數據表示。

思考:

我們可能認為使用全局變挺比使用局部變量自由度大,更方便。一旦定義,所有函數都可直接使用,連函數參數都可省略,甚至函數返回結果個數也不受限制,不需要使用return語句,可以直接通過全局變量回送結果。從表面上看,全局變量確實能實現這些要求,但對於規模較大的程序,過多使用全局變量會帶來副作用,導致各函數間相互干擾。如果整個程序是由多人合作開發的,各人都按自己的想法使用全局變量,相互的干擾可能更嚴重。因此在變量使用中,應盡量使用局部變量,從某個角度看使用似乎受到了限制;但從另一個角度看,它避免了不同函數間的相互干擾,提高了程序質量。

  • 全局變量雖然可以用於多個函數之間的數據交流,但一般情況下,應盡量使用局部變量和函數參數。

靜態變量

1.變量生存周期

變量是保存變化數據的工作單元,計算機用內存單元來對應實現。一旦在程序中定義變量,計算機在執行過程中就會根據變量類型分配相應的內存單元供變量保存數據。
就一般程序而言,計算機都是從主函數開始運行的,使得main函數中所有的局部變量,一開始就在內存數據區中分配了存儲單元。而其他函數在被調用之前,其局部變量並未分配存儲單元,只有當函數被調用時,其形參和局部變量才被分配相應存儲單元;一旦函數調用結束返回主調函數,在函數中定義的所有形參和局部變量將不復存在,相應的存儲單元由系統收回。根據這種特性,把局部變量稱為自動變量,即函數被調用時,系統自動為其局部變量分配存儲單元;一旦該函數結束(不一定是整個程序運行結束),所有分配給局部變量的單元由系統自動回收。變量從定義開始分配存儲單元,到運行結束存儲單元被回收,整個過程稱為變量生存周期。

靜態變量

在靜態存儲區中,除了全局變量外,還有一種特殊的局部變量一一靜態局部變量。它存放在靜態存儲區,不會像普通局部變量那樣因為函數調用結束而被系統回收,它的生存周期會持續到程序結束。由於存儲單元被保留,一旦含有靜態局部變量的函數被再次調用,則靜態局部變量會被重新激活,上一次函數調用后的值仍然保存卷,可供本次調用繼續使用。靜態變量定義格式:

static 類型名 變量表

自動變量如果沒有賦初值,其存儲單元中將是隨機值。就靜態變量而言,如果定義時沒有賦初值,系統將自動賦0。並且賦初值只在函數第一次調用時起作用,以后調用都按前一次調用保留的值使用。這是因為靜態局部變量的生存周期始於函數的第一次調用,貫穿於整個程序。當函數第一次調用時,靜態局部變量的內存單元得以分配,賦以初值,而函數被再次調用時,此靜態局部變量單元已經存在,計算機不會再次為它分配單元,賦初值也不再發生。但靜態局部變量受變量作用范圍限制,不能作用於其他函數(包括主函數)。

  • 靜態變量賦初值只在函數第一次調用時起作用,若沒有賦初值,系統將自動賦值0。

靜態變量與全局變量均位於靜態存儲區,它們的共同點是生存周期貫穿整個程序執行過程。區別在於作用范圍不同,全局變量可作用於所有函數,靜態變量只能用於所定義函數,而不能用於其他函數。靜態變量和全局變量一樣,屬於變量的特殊用法,若沒有靜態保存的要求,不建議使用靜態變量。

  • 除了靜態局部變量外,C語言也宥靜態全局變量,它的作用與程序文件結構有關。

函數應用


解決這個問題,我的代碼一開始是這樣的:

由於這一次我們是將輸入的三個數組合成年月日,然后來判斷合法性,根據排列組合,一共有六種可能需要我們考慮。因此我使用了窮舉法,把六種可能依次搞了一遍。但是,我們看到這六種情況的代碼除了變量的位置以外完全相同,直接這么寫等於把一件事重復做了6遍,感覺這么寫效率好低啊!我們有沒有更好地方法去實現這個功能呢?

使用函數把這段代碼封裝起來,只需要每次改變傳入的參數的順序,即可實現功能。

程序實戰

C語言程序設計——小學生口算刷題系統

參考資料

《C語言程序設計(第3版)》——何欽銘、顏輝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM