125
6 6 函數與巨集 函數與巨集 函數簡介 遞迴函數 變數的儲存等級 前置處理器與巨集 上機實習課程

第六章 函數與巨集

Embed Size (px)

Citation preview

Page 1: 第六章 函數與巨集

第第 66 章 函數與巨集 章 函數與巨集

函數簡介 遞迴函數

變數的儲存等級 前置處理器與巨集

上機實習課程

Page 2: 第六章 函數與巨集

2

函數的原型宣告、定義與呼叫函數的原型宣告、定義與呼叫 (1) (1)

函數原型宣告– 函數原型宣告的語法格式如下:

– 例如一個函數 sum()可接收兩筆成績參數,並 傳回其最後計算總和值,原型宣告如下:

6-1 函數簡介

傳回資料型態 函數名稱 ( 資料型態 參數 1, 資料型態 參數 2, ……….);或

傳回資料型態 函數名稱 (資料型態 , 資料型態 , ……….);

int sum(int score1,int score2);或是int sum(int, int) ;

Page 3: 第六章 函數與巨集

3

函數的原型宣告、定義與呼叫函數的原型宣告、定義與呼叫 (2)(2)

函數的定義– 清楚了函數的原型宣告後,接下來我們要來知道定義函數主體的架構。

– 自訂函數在 C中的定義方式與main()函數類似 ,基本架構如下:

6-1 函數簡介

函數型態 函數名稱 ( 資料型態 參數 1, 資料型態 參數 2, ……….){ 函數主體 ; : return傳回值 ;}

Page 4: 第六章 函數與巨集

4

函數名稱是準備定義函數的第一步,是由設計者自行來命名,命名規則與變數命名規則相符,最

好能具備可讀性。 函數主體是由 C的指令組成,在程式碼撰寫的風格上,我們建議使用註解來說明函數的作用。

如果函數型態宣告為 void,則最後的 return關鍵字可省略,或保留 return,但其後不接傳回值,如:

6-1 函數簡介

return ;

Page 5: 第六章 函數與巨集

5

函數名稱 (引數 1, 引數 2, ……….);

函數的原型宣告、定義與呼叫函數的原型宣告、定義與呼叫 (3)(3)

函數呼叫– 函數呼叫的方式有兩種,假如沒有傳回值,通常直接使用函數名稱即可呼叫函數。

– 語法格式如下:

– 如果函數有傳回值,則可運用指定運算子 "="將傳回值指定給變數。如下所示:

6-1 函數簡介

變數 =函數名稱 (引數 1, 引數 2, ……….);

Page 6: 第六章 函數與巨集

6

函數的實作練習函數的實作練習 (1)(1)

兩筆成績求和函數 sum()– 以下程式範例是整合上述 sum()函數中,包括函數原型宣告、定義與呼叫的完整設計,我們將輸入兩筆成績,並透過函數中的計算,列印出兩筆的總和。

程式範例: sum()函數的實作練習: CH06_01.c

6-1 函數簡介

Page 7: 第六章 函數與巨集

7

6-1 函數簡介

Page 8: 第六章 函數與巨集

8

執行結果

程式解說

6-1 函數簡介

在第 4行中宣告函數原型於 #include引入檔後,主程式之前,也可以宣告在第 7行的大括號後,此函數的參數有 2個。第 17~23行則是函數定義的程式區塊部分。當我們在第 10行中讀入兩數 x、 y時,在第 11行呼叫sum()函數,第 17行中的引數 score1會接收 x的值, score2會接收 y 的值。

Page 9: 第六章 函數與巨集

9

函數的實作練習函數的實作練習 (2)(2)

求取某數的某次方值– 以下程式範例是計算所輸入兩數 x、 y的 xy值函數 Pow(),定將函數定義放在main()函數之前,這樣的做法可以將函數宣告為所謂的「全域範

圍」 。– 程式範例:求取某數的某次方值實作練習:

CH06_02.c

6-1 函數簡介

Page 10: 第六章 函數與巨集

10

6-1 函數簡介

Page 11: 第六章 函數與巨集

11

執行結果

程式解說

6-1 函數簡介

在第 7~15行中,我們定義了函數的主體,由於是在main()函數之前,所以不需再進行函數原型宣告。而第 23行中的 scanf()函數中是用「 ^」字元來作為

輸入間隔字元。

Page 12: 第六章 函數與巨集

12

函數的實作練習函數的實作練習 (3)(3)

畫出長方形圖形函數– 以下程式範例是讓使用者輸入兩個數來計算長

’方形面積,並以 *’畫出長方形圖形。– 在本程式中並沒有傳回值,各位只要使用

return指令即可。 程式範例:畫出長方形圖形函數實作練習:

CH06_03.c

6-1 函數簡介

Page 13: 第六章 函數與巨集

13

6-1 函數簡介

Page 14: 第六章 函數與巨集

14

6-1 函數簡介

Page 15: 第六章 函數與巨集

15

執行結果

程式解說

6-1 函數簡介

在第 5行中宣告無傳回值有參數列的 draw_rect()函數原型,而第 13、 15行中則輸入長與寬的值,並在第 16行中呼叫 rect_display()函數。在第 26行處還要設定所輸入的數字不得小於等於零

,避免印不出圖形。

Page 16: 第六章 函數與巨集

16

函數內的函數原型宣告函數內的函數原型宣告

程式範例:函數內的函數原型宣告實作練習:CH06_04.c

6-1 函數簡介

Page 17: 第六章 函數與巨集

17

6-1 函數簡介

Page 18: 第六章 函數與巨集

18

執行結果

程式解說

6-1 函數簡介

在第 6、 7行中分別宣告了 f_abs()與 cubic_abs()的函數原型,因此在main()函數中可呼叫這些函數。而在第 20行中,因為要在第 21行的 cubic_abs()函數中呼叫 f_abs()函數,所以必須先進行 f_abs()函數的原型宣告。在函數的應用中,如果函數間彼此要相互呼叫,必須在函

數中補上即將呼叫的函數原型宣告。

Page 19: 第六章 函數與巨集

19

全域變數 – 一個全域變數的使用時機應該像是圓周率的設定,例如您可以如下宣告一個變數:

– 由於圓周率是固定的,所以我們可以將之設定為全域變數,以利所有的函數來使用,而為了避免使用者更改了圓周率的值,我們還可使用了 const關鍵字,表示這個變數一經設定之後

就不得更改其值。

變數的有效範圍變數的有效範圍 (1)(1)6-1 函數簡介

const float pi = 3.14159;

Page 20: 第六章 函數與巨集

20

變數的有效範圍變數的有效範圍 (2)(2)

區域變數 – 區域變數只限於函數之中存取,離開該函數之後就失去作用。

– 以下程式範例是宣告了一個全域變數 x,並呼叫setX1()函數時,將 x值設定為 20,這時全域變數 x的值成為 20。

– 而於 setX2()函數中則又宣告了一個區域變數 x,則於函數執行期間,區域變數將暫時覆蓋全域變數,但在函數執行完畢後,又恢復全域變數 x=20的值。

6-1 函數簡介

Page 21: 第六章 函數與巨集

21

變數的有效範圍變數的有效範圍 (3)(3)

程式範例:全域變數與區域變數的宣告與實作: CH06_05.c

6-1 函數簡介

Page 22: 第六章 函數與巨集

22

6-1 函數簡介

Page 23: 第六章 函數與巨集

23

執行結果

程式解說

6-1 函數簡介

在第 5行中宣告全域變數 x,第 9、 10行中則宣告 set1X()與 set2X的函數原型,當在 12行中呼叫 set1X()函數時,第22行中的 x 仍為全域變數,在第 23、 13行中都會輸出20。但在 14行中呼叫 set2X()函數時,由於第 28行所宣告的 x為此程式中的區域變數,因此 28行中會輸出 30,但是一旦離開此函數, x則仍為全域變數了,第 15行中還是會輸出20。

Page 24: 第六章 函數與巨集

24

參數的傳遞參數的傳遞 (1) (1)

傳值呼叫– 傳值呼叫的函數宣告型式如下所示:

– 傳值呼叫的函數呼叫型式如下所示:

6-1 函數簡介

回傳資料型態 函數名稱 ( 資料型態 參數 1, 資料型態參數 2, ……….);或

回傳資料型態 函數名稱 (資料型態 , 資料型態 , ……….);

函數名稱 (引數 1,引數 2, ……….);

Page 25: 第六章 函數與巨集

25

參數的傳遞參數的傳遞 (2)(2)

傳址呼叫– 傳址方式的函數宣告型式如下所示:

– 傳址呼叫的函數呼叫型式如下所示:

6-1 函數簡介

回傳資料型態 函數名稱 ( 資料型態 *參數 1, 資料型 態 *參數 2, ……….);或

回傳資料型態 函數名稱 ( 資料型態 *, 資料型態 *, ……….);

函數名稱 (&引數 1,&引數 2, ……….);

Page 26: 第六章 函數與巨集

26

參數的傳遞參數的傳遞 (3)(3)

程式範例:傳值呼叫與傳址呼叫的宣告與實作: CH06_06.c

6-1 函數簡介

Page 27: 第六章 函數與巨集

27

執行結果

6-1 函數簡介

Page 28: 第六章 函數與巨集

28

程式解說

6-1 函數簡介

有關傳值呼叫 CallByValue()函數與之前作法相同。在第 22行進行傳址呼叫的參數指定時,我們必須使用&「取址運算子」來取出變數 x的記憶體位址,而在第12行要指定值時,則必須使用 *「取值運算子」,告知編譯器將引數指定至參數 x 所指向的位址。

Page 29: 第六章 函數與巨集

29

參數的傳遞參數的傳遞 (4)(4)

程式範例: add()函數的傳址呼叫宣告與實作: CH06_07.c

6-1 函數簡介

Page 30: 第六章 函數與巨集

30

執行結果

6-1 函數簡介

Page 31: 第六章 函數與巨集

31

程式解說

6-1 函數簡介

在第 3行中宣告傳址呼叫的函數原型宣告,而第 10行中則將參數 a與 b的位址傳遞到第 17行中 add()函數,並由 *「取值運算子」,告知編譯器將引數p1、 p2 指定至參數所指向的位址。

Page 32: 第六章 函數與巨集

32

參數的傳遞參數的傳遞 (5)(5)

程式範例: exchange()函數的傳址呼叫宣告與實作: CH06_08.c

6-1 函數簡介

Page 33: 第六章 函數與巨集

33

6-1 函數簡介

Page 34: 第六章 函數與巨集

34

執行結果

程式解說

6-1 函數簡介

在第 4行中建立傳址呼叫函數 exchange()的原型宣告,第 13行中則由主程式中取得兩個數值。接下來於第 13行中呼叫 ecxhange()函數,並傳遞兩個參數位址給該函數。第 25~26 行則進行數值的交換。

Page 35: 第六章 函數與巨集

35

參數的傳遞參數的傳遞 (6)(6)

程式範例: Average()函數的傳值與傳址呼叫同步實作範例: CH06_09.c

6-1 函數簡介

Page 36: 第六章 函數與巨集

36

6-1 函數簡介

Page 37: 第六章 函數與巨集

37

執行結果

程式解說

6-1 函數簡介

在第 4行中的 average()函數原型宣告中,同時具備了傳值與傳址呼叫兩種方式的參數。第 11行則可輸入兩筆成績,分別存入 Chi與 Eng兩個變數。第 14行中則呼叫 average()函數。第 25行中則由變數 c與主程式中的 Ave 共用一位址。

Page 38: 第六章 函數與巨集

38

遞迴函數 遞迴函數

定義如下:

6-2 遞迴函數

假如一個函數或副程式,是由自身所定義或呼叫的, 就稱為遞迴 (Recursion) ,它至少要定義 2種條件,

包括一個可以反覆執行或呼叫的過程,與一個跳出執行過程的出口。

Page 39: 第六章 函數與巨集

39

遞迴的定義遞迴的定義

可以區分為以下兩種:– 直接遞迴 (Direct Recursion)

指遞迴函數中,允許直接呼叫該函數本身,稱為直接遞迴 (Direct Recursion)。

– 間接遞迴 指遞迴函數中,如果呼叫其他遞迴函數,再從其

他遞迴函數呼叫回原來的遞迴函數,我們就稱做間接遞迴 (Indirect Recursion)。

6-2 遞迴函數

Page 40: 第六章 函數與巨集

40

階乘函數實作階乘函數實作 (1)(1)

3 階乘等於 3×2×1=6,而 0 階乘則定義為 1。 “ ”我們一般以符號 ! 來代表階乘。 如 4 階乘可寫為 4!。 任何問題想以遞迴式來表示,一般需要符合兩個

條件:一個反覆的過程,以及一個跳出執行的缺口。

秉持這兩個原則, n!可以寫成:

6-2 遞迴函數

n!=n×(n-1)*(n-2)……*1

Page 41: 第六章 函數與巨集

41

階乘函數實作階乘函數實作 (2)(2)

程式範例:階乘函數 (n!)的實作範例:CH06_10.c

6-2 遞迴函數

Page 42: 第六章 函數與巨集

42

6-2 遞迴函數

Page 43: 第六章 函數與巨集

43

執行結果

程式解說

6-2 遞迴函數

在第 11行中輸入要計算的階乘數。第 13~14行中將列印出 1! 到 n!的所有結果。第 23行中是設定跳出遞迴反覆執行過程中的缺口。第 26行中則是執行遞迴程式的過程。

Page 44: 第六章 函數與巨集

44

基本定義:

從費伯那序列的定義,也可以嘗試把它轉成遞迴的形式:

費伯那序列實作費伯那序列實作 (1) (1) 6-2 遞迴函數

Page 45: 第六章 函數與巨集

45

費伯那序列實作費伯那序列實作 (2)(2)

程式範例:費伯那序列的實作範例:CH06_11.c

6-2 遞迴函數

Page 46: 第六章 函數與巨集

46

6-2 遞迴函數

Page 47: 第六章 函數與巨集

47

執行結果

程式解說

6-2 遞迴函數

第 18~27行中定義了 fib()函數,並在第 10行中輸入 n值。第 21、 23行中,判斷是否為第 0、 1、 2 項的費式數列值,如不是則執行第 26行,以遞迴式計算出第 n 項費

式數列值。

Page 48: 第六章 函數與巨集

48

autoauto變數變數 (1) (1)

使用 auto表示要宣告自動變數( automatic variable ),自動變數也就是區域變數,當您在宣告變數時沒有指定型態修飾詞,就會自動設定為 auto。

自動變數是在進入函數區塊後,系統才配置記憶體空間給該變數,當離開該函數區塊,便將所配罝的記憶體空間歸還給系統。

它的宣告語法為:

6-3 變數的儲存等級

auto 資料型態 變數名稱 = 初始值;

Page 49: 第六章 函數與巨集

49

autoauto變數變數 (2)(2)

程式範例: auto 修飾詞變數的宣告範例:CH06_12.c

6-3 變數的儲存等級

Page 50: 第六章 函數與巨集

50

6-3 變數的儲存等級

Page 51: 第六章 函數與巨集

51

執行結果

程式解說

6-3 變數的儲存等級

在mail()函數中宣告 auto變數 i,這時的 auto關鍵字也可省略,此時 i為此函數中的區域變數。請注意! auto變數不可宣告在第 7行之前,否則會發生錯誤。第 20、 25行中也都宣告了 auto變數,但還是僅能

供該函數使用。

Page 52: 第六章 函數與巨集

52

externextern變數變數 (1)(1)

宣告語法:

例如底下的例子:

6-3 變數的儲存等級

extern 資料型態 變數名稱 = 初始值;

Page 53: 第六章 函數與巨集

53

externextern變數變數 (2)(2)

程式範例: extern 修飾詞變數的宣告範例:CH06_13.c

6-3 變數的儲存等級

Page 54: 第六章 函數與巨集

54

執行結果

6-3 變數的儲存等級

Page 55: 第六章 函數與巨集

55

程式解說

6-3 變數的儲存等級

在第 20行中宣告了一個外部變數 PI,如果要在main()函數中使用,那麼必須於第 7 行中宣告 PI 為 extern變數,就可於第 13行中將 PI變數用於

計算圓面積的公式計算。

Page 56: 第六章 函數與巨集

56

registerregister變數變數

使用 register 識別字來宣告變數,該變數將使用 CPU的暫存器來儲存,由於 CPU的暫存器速度較快,因而可以加快變數存取的效率,它的宣告語法如下:

6-3 變數的儲存等級

register 資料型態 變數名稱 = 初始值;

Page 57: 第六章 函數與巨集

57

以下是它的宣告語法:

在宣告靜態區域變數同時,如果各位沒有設定初始值的話,系統自動將靜態變數初始值設定為 0,而一般的變數初始值,在未設定初始值

的情況下,則是一個不確定值。

staticstatic變數變數 (1)(1)6-3 變數的儲存等級

static 資料型態 變數名稱 = 初始值;

Page 58: 第六章 函數與巨集

58

staticstatic變數變數 (2)(2)

程式範例: static 修飾詞變數的宣告範例:CH06_14.c

6-3 變數的儲存等級

Page 59: 第六章 函數與巨集

59

6-3 變數的儲存等級

Page 60: 第六章 函數與巨集

60

執行結果

程式解說

6-3 變數的儲存等級

第 11行中,輸入所要計算的階層數。第 23行則使用 static來宣告變數 count,注意到使用 static宣告變數時,該變數將只被啟始一次,所以我們利用 static宣告的變數於函數結束後可以保留變數值的特性,在第 26行處以計算遞迴呼叫的次

數。

Page 61: 第六章 函數與巨集

61

#include語法有兩種指定方式:

在 #include之後使用角括號 <>,前置處理器將至預設的系統目錄中尋找指定的檔案。

“”使用雙引號 來指定檔案,則前置處理器會先尋找目前程式檔案的工作目錄中是否有指定的檔案。

#include #include 指令 指令6-4 前置處理器與巨集

#include <檔案名稱 >#include "檔案名稱 "

Page 62: 第六章 函數與巨集

62

語法如下所示:

例如 #define常用於以有意義的名稱取代某個常數,這和使用關鍵字 const來定義常數類似,下面程式範例使用 #define巨集指令來定義PI為 3.14159。

不同之處在於「取代」的差別,在這兩行程式碼中,前置處理器並不會理會第一行程式碼,pi只是一個變數名稱,然而前置處理器會將 PI取代為 3.14159 。

#define#define指令指令 (1) (1) 6-4 前置處理器與巨集

#define 巨集名稱 表示式

const float pi = 3.14159;#define PI 3.14159

Page 63: 第六章 函數與巨集

63

#define#define指令指令 (2)(2)

程式範例: #define巨集的常數取代功能範例: CH06_15.c

6-4 前置處理器與巨集

Page 64: 第六章 函數與巨集

64

執行結果

程式解說

6-4 前置處理器與巨集

第 3行定義巨集來取代常數。在進行編譯時,前置處理器會先行將程式中所有的PI置換為 3.14159,然後再進行程式的編譯。

Page 65: 第六章 函數與巨集

65

#define#define指令指令 (3)(3)

程式範例: #define巨集的字串取代功能範例: CH06_16.c

6-4 前置處理器與巨集

Page 66: 第六章 函數與巨集

66

執行結果

程式解說

6-4 前置處理器與巨集

第 3行中定義巨集指令為 Justin字串 ,並跳行,而第 7行中由於 AUTHOR “”這是被雙引號 包括住的字串,所以它被視為字串輸出,前置處理器並不會將它如巨集指令般展開。至於第 9行的 AUTHOR並沒有使用雙引號包括,所以前置處理器將之展開為 "Justin",並跳行。

Page 67: 第六章 函數與巨集

67

#define#define指令指令 (4)(4)

程式範例: #define巨集的無引數函數取代功能範例: CH06_17.c

6-4 前置處理器與巨集

Page 68: 第六章 函數與巨集

68

執行結果

6-4 前置處理器與巨集

Page 69: 第六章 函數與巨集

69

程式解說

6-4 前置處理器與巨集

其實這個程式範例仍然是簡單的巨集取代動作,前置處理器會將所有的 NEWLINE 展開為 printf("\n"),如第 9、 11行,而 DRAWLINE會展開為draw_line()函數,如第 8、 10 行。

Page 70: 第六章 函數與巨集

70

#define#define指令指令 (5)(5)

程式範例: #define巨集的有引數函數取代功能範例: CH06_18.c

6-4 前置處理器與巨集

Page 71: 第六章 函數與巨集

71

執行結果

程式解說

6-4 前置處理器與巨集

第 4行中定義了有引數的巨集函數 C(F),可做為攝氏溫度轉華氏之用,請注意在括號間不得有空白,否則空白之後會被視為表示式,而編譯時就會發生錯誤。第 12行中的 C(Fx)在編譯時已被直接取代為(Fx-32)*5/9。

Page 72: 第六章 函數與巨集

72

#define#define指令指令 (6)(6)

程式範例: #undef語法的宣告與使用範例:CH06_19.c

6-4 前置處理器與巨集

Page 73: 第六章 函數與巨集

73

執行結果

6-4 前置處理器與巨集

Page 74: 第六章 函數與巨集

74

程式解說

6-4 前置處理器與巨集

在此程式中重複定義一個巨集名稱,因此在第11行處使用了 undef指令解除第一次定義的DIVIDE巨集。然後才重新於第 13行定義 DIVIDE 。

Page 75: 第六章 函數與巨集

75

條件編譯指令條件編譯指令 (1) (1)

#ifdef 條件編譯– #ifdef用來判斷巨集名稱是否已經定義過,如果

已定義則編譯區塊中的陳述句,否則就不進行編譯。語法如下所示:

6-4 前置處理器與巨集

#ifdef 巨集名稱 陳述句#endif

Page 76: 第六章 函數與巨集

76

條件編譯指令條件編譯指令 (2)(2)

程式範例: #ifdef 條件編譯語法的宣告與使用範例: CH06_20.c

6-4 前置處理器與巨集

Page 77: 第六章 函數與巨集

77

執行結果

6-4 前置處理器與巨集

Page 78: 第六章 函數與巨集

78

程式解說

6-4 前置處理器與巨集

由於中第 3行 DEBUG名稱已被定義,第 11~13行 #ifdef…#endif區塊中的程式碼才會被編譯。如果您將第 3行中的 DEBUG定義移除再進行編

譯,程式的結果顯示就不會再有除錯的內容。

Page 79: 第六章 函數與巨集

79

條件編譯指令條件編譯指令 (3)(3)

#ifndef 條件編譯– #ifndef語法的作用與 #ifdef 正好相反,如果巨集名稱沒有定義,則會編譯 #ifndef區塊中的陳述句,語法如下所示:

6-4 前置處理器與巨集

#ifndef 巨集名稱 陳述句#endif

Page 80: 第六章 函數與巨集

80

條件編譯指令條件編譯指令 (4)(4)

程式範例: #ifndef 條件編譯語法的宣告與使用範例: CH06_21.c

6-4 前置處理器與巨集

Page 81: 第六章 函數與巨集

81

執行結果

6-4 前置處理器與巨集

Page 82: 第六章 函數與巨集

82

程式解說

6-4 前置處理器與巨集

在這個程式中,如果已經自行定義 ON與 OFF,則 #ifndef區塊中的程式碼將不會被編譯,區塊中的 #define也不會被展開。第 6~8行與第 11~14行中用來執行當 ON與 OFF

未定義時的執行步驟。

Page 83: 第六章 函數與巨集

83

條件編譯指令條件編譯指令 (5)(5)

程式範例: NULL的重新定義範例: CH06_22.c

6-4 前置處理器與巨集

Page 84: 第六章 函數與巨集

84

執行結果

程式解說

6-4 前置處理器與巨集

第 6~8行中,如果 NULL 已定義,則輸出 NULL的值。第 9行中解除 C中對 NULL的定義,而第 10~13行則將 NULL定義為 -1 。

Page 85: 第六章 函數與巨集

85

條件編譯指令條件編譯指令 (6)(6)

#if、 #else、 #elif 條件編譯– 語法如下所示:

6-4 前置處理器與巨集

Page 86: 第六章 函數與巨集

86

條件編譯指令條件編譯指令 (7)(7)

程式範例: NULL的重新定義範例: CH06_23.c

6-4 前置處理器與巨集

Page 87: 第六章 函數與巨集

87

執行結果

程式解說

6-4 前置處理器與巨集

第 6行利用 #if 條件編譯來判斷,第 9行則是利用 #else 條件編譯指令,不過必須搭配 #if指令,形成和 if else 條件敘述類似的功能。

Page 88: 第六章 函數與巨集

88

上機實習課程上機實習課程 (1)(1)

上機實習範例: CH06_24.c– 請設計一函數 square(x),讓使用者輸入實數 x值,並傳回 x2 的實數值。

6-5 上機實習課程

Page 89: 第六章 函數與巨集

89

執行結果

6-5 上機實習課程

Page 90: 第六章 函數與巨集

90

上機實習課程上機實習課程 (2)(2)

上機實習範例: CH06_25.c– 延續 CH06_24.c範例,請再自行設計一函數

cubic(x),讓使用者輸入實數 x值,並傳回 x3

的實數值,此外還要設計一函數 F(x)=2 x3+3 x2,輸出 F(125) 的值。

6-5 上機實習課程

Page 91: 第六章 函數與巨集

91

6-5 上機實習課程

Page 92: 第六章 函數與巨集

92

上機實習課程上機實習課程 (3)(3)

執行結果

上機實習範例】: CH06_26.c – 請各位以遞迴式來設計一河內塔函數,當輸入

要移動的盤子數量時,能輸出所有移動過程。

6-5 上機實習課程

Page 93: 第六章 函數與巨集

93

6-5 上機實習課程

Page 94: 第六章 函數與巨集

94

執行結果

6-5 上機實習課程

Page 95: 第六章 函數與巨集

95

上機實習課程上機實習課程 (4)(4)

上機實習範例: CH06_27.c – 請試著撰寫一個傳址呼叫長度轉換函數,由使用者輸入英呎及英吋,並同步轉換成公尺及公分。提示如下:

6-5 上機實習課程

1 英呎 =12 吋; 1 吋 =2.54 公分

Page 96: 第六章 函數與巨集

96

6-5 上機實習課程

Page 97: 第六章 函數與巨集

97

執行結果

6-5 上機實習課程

Page 98: 第六章 函數與巨集

98

上機實習課程上機實習課程 (5)(5)

上機實習範例: CH06_28.c– 以下這個程式範例是利用 #define指令定義一個巨集 FUNCTION來計算 x3+5x2的值,特別提醒您在巨集中所定義的 x於主程式中仍須宣告。

6-5 上機實習課程

Page 99: 第六章 函數與巨集

99

執行結果

6-5 上機實習課程

Page 100: 第六章 函數與巨集

100

上機實習課程上機實習課程 (6)(6)

上機實習範例: CH06_29.c– 以下這個程式範例是利用 #define指令定義一個簡單計算圓面積的巨集函數,並且可以傳遞半徑為參數,讓使用者輸入半徑即可算出圓面積。

6-5 上機實習課程

Page 101: 第六章 函數與巨集

101

執行結果

6-5 上機實習課程

Page 102: 第六章 函數與巨集

102

上機實習課程上機實習課程 (7)(7)

上機實習範例: CH06_30.c– 請設計以非遞迴方式 (建議利用 for迴圈 )來計算 n!的值。

6-5 上機實習課程

Page 103: 第六章 函數與巨集

103

執行結果

6-5 上機實習課程

Page 104: 第六章 函數與巨集

104

上機實習課程上機實習課程 (8)(8)

上機實習範例: CH06_31.c– 請各位先在外部檔案 myfun.h中定義階乘函數

factorial() 及平方值函數 square(),並將其含括到程式中,再利用這兩個函數來計算如下數列的值:

6-5 上機實習課程

Page 105: 第六章 函數與巨集

105

6-5 上機實習課程

Page 106: 第六章 函數與巨集

106

myfun.h

6-5 上機實習課程

Page 107: 第六章 函數與巨集

107

執行結果

上機實習範例: CH06_32.c– 在此函數中我們使用了兩種參數傳遞模式,傳址與傳址呼叫。

– 其中記錄加權比例的變數是使用傳址呼叫,當函數中變數改變時,main() 函數中也會同步改變。

6-5 上機實習課程

Page 108: 第六章 函數與巨集

108

6-5 上機實習課程

Page 109: 第六章 函數與巨集

109

6-5 上機實習課程

Page 110: 第六章 函數與巨集

110

上機實習課程上機實習課程 (9)(9)

執行結果

上機實習範例: CH06_33.c– 這個範例會要求您設計一個輸入兩個數值,利

用輾轉相除法計算最大公因數的函數。

6-5 上機實習課程

Page 111: 第六章 函數與巨集

111

6-5 上機實習課程

Page 112: 第六章 函數與巨集

112

執行結果

6-5 上機實習課程

Page 113: 第六章 函數與巨集

113

上機實習課程上機實習課程 (10)(10)

上機實習範例: CH06_34.c– 用傳值呼叫的方式重新設計 CH06_33.c程式,由主程式接收兩個參數,並將這兩個參數傳給gcd()函數進行最大公因數的運算,接著也可利

用最大公因數來求取兩者最小公倍數。

6-5 上機實習課程

Page 114: 第六章 函數與巨集

114

6-5 上機實習課程

Page 115: 第六章 函數與巨集

115

執行結果

6-5 上機實習課程

Page 116: 第六章 函數與巨集

116

上機實習課程上機實習課程 (11)(11)

上機實習範例: CH06_35.c– 在以下程式範例中,說明了雖然已經分別宣告了兩個相同的 Sum變數,但是由於它們所處的程式區段及佔用的記憶體位址不同,所以它們之間並沒有關聯。

6-5 上機實習課程

Page 117: 第六章 函數與巨集

117

執行結果

6-5 上機實習課程

Page 118: 第六章 函數與巨集

118

上機實習課程上機實習課程 (12)(12)

上機實習範例: CH06_36.c – 這個程式範例主要是設計公尺轉英呎的函數,並讓您了解暫存器變數的宣告及使用方式。

– 基本上,對於一般的程式設計師而言,使用到暫存器變數的機會並不多。

6-5 上機實習課程

Page 119: 第六章 函數與巨集

119

執行結果

6-5 上機實習課程

Page 120: 第六章 函數與巨集

120

上機實習課程上機實習課程 (13)(13)

上機實習範例: CH06_37.c – 以下利用一個簡單的程式範例來為您說明在在迴圈中函數呼叫時,函數中 static變數及 auto變數的差異。

6-5 上機實習課程

Page 121: 第六章 函數與巨集

121

執行結果

6-5 上機實習課程

Page 122: 第六章 函數與巨集

122

上機實習課程上機實習課程 (14)(14)

上機實習範例: CH06_38.c– 以下程式範例中編譯器會將程式中所有

MAX(a,b)的名稱,替換成定義的算式。– 編譯器替換算式的同時,也會把引數 a與 b值

代入替換之後的計算式中。

6-5 上機實習課程

Page 123: 第六章 函數與巨集

123

執行結果

6-5 上機實習課程

Page 124: 第六章 函數與巨集

124

上機實習課程上機實習課程 (15)(15)

上機實習範例: CH06_39.c– 以下程式範例說明當 #if指令的運算式成立

(Use_MACRO == 1)時,則第 7行的定義巨集才會執行,而主函數main()即可以使用MAX 巨集。

6-5 上機實習課程

Page 125: 第六章 函數與巨集

125

執行結果

6-5 上機實習課程