明解C++教學手冊 柴田望洋 博士 著 書號:PG20269
第五章 函數的基本 函數就是由一連串的處理匯整而成的程式組件。本章所要學習的就是函數的基本知識。
5-1 函數 函數 函數(function)是程式的組件,它是由一連串的處理匯整而成。 函數的定義如下:
未使用函數的程式:
使用了函數的程式:
可在函數呼叫運算式中賦予引數(argument),而被呼叫之函數所產生的參數(parameter),則會以引數的值來初始化。
跳躍敘述 Break敘述、continue敘述、return敘述和goto敘述統稱為跳躍敘述(jump statement)。
main函數 使用函數改寫List 2-10的程式如下:
函數原型宣告 被呼叫方的函數要定義在前面,而呼叫方的函數則必須定義在後面。 錯誤:找不到函數max的宣告
爲了呼叫沒有定義在前面的函數,所以才需要函數原型宣告(function prototype declaration)。
傳值 將值作為引數來交換的機制,就稱為傳值(pass by value)。
活用傳值的優點就能讓函數更為簡潔。
不接收引數的函數 判斷函數呼叫運算式所得到的值會是true或false。
void函數 不會傳回值的函數之傳回值型態必須宣告為void。
函數的泛用性 此程式將任意字元排列為直角三角形。
預設引數和引數的型態 在函數原型宣告中設定預設引數(default argument)之後,就可以在呼叫函數時省略引數了。 傳遞和參數不同型態的引數時,會視需要進行型態轉換。
5-2 參照和傳值 傳值的極限 右側程式必須以傳址(pass by reference)來實現:
參照 在理解何謂傳址之前,必須先瞭解參照(reference)。
傳址 下列程式為以傳址改寫的List 5-12:
傳值和傳址的差異: 傳值 ─ 引數的值不可能被改寫。 傳址 ─ 引數的值有可能被改寫。
三個值的排序
先比較a和b的值,若a大於b就將它們的值交換。 再比較b和c的值,若b大於c就將它們的值交換。 c的值已經是最大值,接著比較a和b的值,並將較大一方的值存放在b。
5-3 試著調查整數的內部 整數的內部 無符號整數的內部表示
有符號整數的內部表示
無符號整數/有符號整數的表示範圍:
位元單位的邏輯運算 「&」叫做位元積運算子(biteise AND operator)。 「|」叫做位元和運算子(bitwise inclusive operator)。 「^」叫做位元差運算子(bitwise exclusive OR operator)。 「~」叫做補數運算子(complement operator)。
位移運算 「<<」運算子和「>>」運算子統稱為位元單位的位移運算子(bitwise shift operator)。
邏輯位移和算數位移
計算位元數 取得unsigned型態的位元數 顯示位元內容
5-4 生存空間和生命週期 生存空間 生存空間(scope)是用來劃分變數的適用範圍。 生存空間可分為: 5-4 生存空間和生命週期 生存空間 生存空間(scope)是用來劃分變數的適用範圍。 生存空間可分為: 檔案生存空間 區塊生存空間 「::」就是範圍解析運算子(scope resolution operator)。
生命週期 變數的壽命就是生命週期(storage duration),可以使用記憶類別指定字(storage duration specifier)來指定變數的生命週期。
生命週期可分為: 自動生命週期 (automatic storage duration) 沒有加上記憶類別指定字來定義的物件。 靜態生命週期 (static storage duration) 加上static來宣告的物件。 動態生命週期 (dynamic storage duration) 將在第六章學習。
傳回參照的函數
5-5 多載和行內函數 函數的多載 定義多個名稱名稱相同的函數,就稱為函數的多載(overloading)。 5-5 多載和行內函數 函數的多載 定義多個名稱名稱相同的函數,就稱為函數的多載(overloading)。 多載的函數之引數型態與個數一定要不同。 對於進行類似處理的函數,就可以給予相同名稱來多載。 main函數無法進行多載。
行內函數 較短的函數可以定義為行內函數(inline function)。 行內函數不會使程式的執行速度降低。 行內函數的定義如下:
總結 一連串的處理可以匯整成函數(程式組件)來實作。 函數是透過傳回值型態、名稱、參數的個數和型態來被賦予特徵。函數的主體是區塊。 可以對不同的函數給予相同的名稱來進行多載。不過,這些函數必須可以透過參數的個數和型態來識別。 函數所接收到的參數會以呼叫方所傳遞的引數來初始化。 原則上,引數的傳遞是以傳值來進行。因此,即使改變接收到的參數的值,引數的值也不會跟著改變。 在呼叫時所省略的引數,會自動地以預設引數來填補。
在函數內進行return敘述時,程式的流程就會回到呼叫源。如果不是void函數的話,就可以在回到呼叫源時將值傳回。 只要判斷函數呼叫運算式,就可以得到被傳回的值。 傳回參照的函數之呼叫運算式,會變成可以放在指定的左邊的左值運算式。 加上inline來定義的行內函數,會被展開並嵌入程式之中。規模較小且要求高速性的函數,最好是設為行內函數。 和行內函數相似的是類似函數巨集,使用時必須考量是否會有副作用。 被呼叫方的函數要在前面定義,而呼叫方的函數則要在後面定義。 為了呼叫沒有在前方定義的函數,就需要函數原型宣告。
在函數之外定義的變數,擁有到檔案尾端為止都可使用其名稱的檔案生存空間。而在函數之中定義的變數,則擁有到區塊尾端為止都可使用其名稱的區塊生存空間。 同時存在著名稱相同但生存空間不同的變數時,可以看見位於較內側者,而看不見位於較外側者。只要使用範圍解析運算子「::」,就可以存取擁有檔案生存空間的變數。 在函數之外定義的物件,以及加上static且在函數之中定義的物件,都擁有從程式開始到結束為止都存在的靜態生命週期。當沒有明確地初始化時,則會以0來初始化。 在函數之中且沒有加上static來定義的物件,會擁有到區塊尾端為止都存在的自動生命週期。當沒有明確地初始化時,則會以不定值來初始化。