Download presentation
Presentation is loading. Please wait.
1
第3章 變數、算術運算、 數學函數及輸入輸出
2
第3章 變數、算術運算、數學函數及 輸入輸出 3.1 變數:命名、宣告、指定及列印值 3.2 常數巨集及更多有關的列印變數的值
3.3 算術算子與算式 3.4 混合型算術,複合指定,運算的優先順序及 強迫轉換型別 3.5 由鍵盤讀取資料 3.6 由檔案讀取資料 3.7 數學庫存函數 3.8 把輸出寫入檔案 3.9 單一字元資料
3
3.1 變數:命名、宣告、指定及列印值 課題: 變數命名 宣告資料型態 使用指定敘述 顯示變數的值 基本指定敘述
4
3.1 變數:命名、宣告、指定及列印值 我們如何宣告變數? 我們要如何宣告超過一個變數? 宣告變數的效果為何? 我們如何命名變數?
甚麼是關鍵字? 以概念來說,當程式開始執行時,在記憶體中發生甚麼事? 甚麼是一個指定敘述? 如何顯示變數或常數的值在螢幕上?
5
3.1 變數:命名、宣告、指定及列印值 變數宣告
6
3.1 變數:命名、宣告、指定及列印值 我們如何命名變數?C程式中的變數是以它們的名稱辨別
的。變數名稱被分類為識別字。所以變數的命名方式必須 遵守識別字所採用的規則。 (續下頁)
7
3.1 變數:命名、宣告、指定及列印值 (續上頁) 一些識別字的限制 (續下頁)
8
1apple interest_ rate% float apple interest_rate xfloat
3.1 變數:命名、宣告、指定及列印值 (續上頁) 不合規定的變數名稱範例: 1apple interest_ rate% float In come one.two 合乎規定的變數名稱範例: apple interest_rate xfloat Income one_two
9
3.1 變數:命名、宣告、指定及列印值 在本課程的程式中頭三個指定敘述被執行過後,表格會如以 下所示的樣子。
在第四個及第五個指定敘述執行過後,表格成為
10
3.1 變數:命名、宣告、指定及列印值 甚麼是一個指定敘述?一個指定敘述指派一個值給 一個變數,也就是說指定敘述導致一個值被存到變
數的記憶體儲存格。 指定敘述
11
3.1 變數:命名、宣告、指定及列印值 printf( )函數可以被用來把一個變數或常數的值顯示 在螢幕上。語法是:
其中格式化字串是一個具有三種要素的文字字: 第一種是ANSI C所稱的普通字元。這字元會毫不改變地顯示在螢幕上。 第二種是轉換指示,被用來把引數從引數列 中轉換、格式化及顯示出來。 第三種是printf函數用來控制 游標或插入點的脫離序列。(續下頁)
12
3.1 變數:命名、宣告、指定及列印值 (續上頁) 引數與轉換指示
13
3.2 常數巨集及更多有關的列印變數的值 課題: 使用define指令來定義常數 更多有關轉換指令及它們的元件。 科學記號 轉換指定字中的旗標
14
3.2 常數巨集及更多有關的列印變數的值 一個常數巨集是經由一個前置處理器指令建立的。 我們如何建立一個常數巨集?
前置處理器如何與define指令一起運作? 命名常數巨集的習慣為何? ANSI C如何轉換一個浮點數為科學記號? int及float型資料格式化指示的完整結構為何? 如果顯示一個整數或浮點數時的欄位寬度小於或 大於實際需要,或者沒有宣告,則會發生甚麼? 如果顯示一個浮點數時精確位數小於或 大於實際需要,或者沒有宣告, 則會發生甚麼?(續下頁)
15
3.2 常數巨集及更多有關的列印變數的值 旗號 - 是用來做甚麼的?
(續上頁) 旗號 - 是用來做甚麼的? 不同的轉換指示會如何顯示365,3.1416及 ? 給定相同的值和使用相同的格式,用不同的編譯器建立的程式會產生完全相同的輸出嗎? 如果我們用%f顯示一個int或用%d顯示一個float會怎樣? 在做工程方面的程式設計時,使用%f型顯示格式有 危險嗎? 為甚麼要這麼留意printf敘述?
16
3.2 常數巨集及更多有關的列印變數的值 格式化指示的完整結構為 %[旗號][欄位寬度][.精確位數]型別 (續下頁)
17
3.2 常數巨集及更多有關的列印變數的值 (續上頁) ANSI C中的旗號與型別
18
3.2 常數巨集及更多有關的列印變數的值
19
3.2 常數巨集及更多有關的列印變數的值
20
3.2 常數巨集及更多有關的列印變數的值
21
3.3 算術算子與算式 課題: 運算元 算術算子及其性質 算術算式
22
3.3 算術算子與算式 甚麼是一個算術算式? 一個算術算式的元件是甚麼? 甚麼可以作為一個運算元? 算子 ++,- - 及 % 的意義為何?
一個算術算式是一個完整的C敘述嗎?如何用在一個指定敘述中? 一個單一變數可以視作一個算式嗎? 如果我們試著把一個數字除以0會怎樣? 如果在我們程式中發生這個問題,我們該怎麼辦? 我們如何找到這個敘述? (續下頁)
23
3.3 算術算子與算式 如果沒有printf敘述在錯誤發生前被執行該如何? 一旦我們知道錯誤的大約位置,我們該做甚麼?
(續上頁) 如果沒有printf敘述在錯誤發生前被執行該如何? 一旦我們知道錯誤的大約位置,我們該做甚麼? 我們現在該如何改正問題? 有更容易找到錯誤所在的方法嗎?
24
3.3 算術算子與算式 算子 + + 是一個遞增算子,可以放在變數的前方或後方(但不可都放)。
i ++ 可以解釋為敘述 i = i + 1; 算子 - - 是一個遞減算子,會使變數的值減少1 。 i - - 可以解釋為敘述 i = i - 1; 算子 % 是一個餘數算子,必須要置於兩個變數或常數之間。 k%p的意義為k被p除的餘數。
25
3.3 算術算子與算式 尋找溢位錯誤的來源
26
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
課題: 算術運算的優先順序 變數的初始化 算術敘述中的陷阱 在算術算中混合整數及浮點數 強迫轉換型別 副作用
27
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
我們如何初始化變數? 假設int型變數i與j都等於1,k=i + +;的意義和h= + + j;是否相同? C如何解釋並儲存本課程程式中的6? C如何解釋並儲存本課程程式中的4.0? 6/4的值為何? 6.0/4.0的值為何? 6/4.0的值為何? 如果我們指派一個浮點數型的值給一個宣告為整數 型的變數會怎樣? 如果我們把一個整數型的值指派給一個浮點數 型變數會怎樣? (續下頁)
28
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
(續上頁) 雖然在本課程程式中沒有出現,但算式(-6/5)的結果為何? C執行算術的方式對寫程式的影響為何? 我們可以修改C在算術運算中使用型別的方式嗎? 強迫轉型算子的一般式為何? 算子 + =,- =,* =,/ = 及 % = 的意義為何? 我們如何控制算術算式中的優先須序? 如果所有的算子都有相同程度的優先須序會怎樣? 在一個算式中我們可以連續使用兩個算子嗎? 那些算子可以用在一個算術算式中? (續下頁)
29
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
算術算子
30
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
(續上頁) 表格3.6中的運算元數目,位置,結合性及優先須序是甚麼意思? 強迫轉型算子受優先須序影響嗎? 強迫轉型算子的使用受圖3-7解說的C算術運算規則影響嗎? 副作用是甚麼? 副作用產生的危險是那些?
31
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
(續下頁)
32
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
(續上頁)
33
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
k=i + + ,i的值先被指派給變數k。指派完畢後,變數i的值被後置型遞增算子+ +由1增加為2。所以,在執行完k=i + + ;後,i=2而k=1。 h= + + j ,j的值首先被前置型遞增子+ +由1增加為2。增加完畢後,新的j值2被指派給變數h。所以,在執行完h= + + j;後,j=2且h=2。 (續下頁)
34
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
(續上頁) 敘述k=i + + ;相當於敘述 k=i; i=i + 1; 但是敘述h= + + j;相當於 j=j + 1; h=j; (續下頁)
35
3.4 混合型算術,複合指定,運算的優先 順序及強迫轉換型別
(續上頁) 這一類算子的規則如下: 如果遞增或遞減算子是置於變數之前,則變數是先被增加或減少1。然後算式是用新的變數值來計算。 如果遞增或遞減算子是置於變數之後,則算式先執行計算。然後變數才被增加 或減少。
36
3.4 混合型算術,複合指定,運算的優先順序及 強迫轉換型別
37
3.4 混合型算術,複合指定,運算的優先順序及 強迫轉換型別
38
3.4 混合型算術,複合指定,運算的優先順序及 強迫轉換型別
如果在敘述中沒有採用強迫轉型算子,則結果會變成 所以我們可以看出強迫轉型算子改變了變數xx及cc儲存的結果。
39
3.5 由鍵盤讀取資料 課題: 使用scanf()函數 由鍵盤輸入資料 位址算子& double型資料
40
3.5 由鍵盤讀取資料 什麼是double型資料? 我們如何由鍵盤輸入資料? 你可以說更多有關符號 & 嗎?
scanf函數中的文字字串有哪些元件? 在使用scanf時常犯的錯誤是那些?
41
3.5 由鍵盤讀取資料 double型與float型對比
42
3.5 由鍵盤讀取資料 使用scanf()輸入
43
3.5 由鍵盤讀取資料 scanf函數的動作
44
3.6 由檔案讀取資料 課程: 開始與關閉一個檔案 從一個檔案讀取資料 使用fscanf()函數
45
3.6 由檔案讀取資料 哪一個函數最常被用來從一個檔案中讀取資料? 什麼是一個檔案指標? 命名檔案指標的方式為何?
在宣告了檔案指標之後,我們如何使一個檔案可供讀取? 你可以說更多有關於FILE的嗎? 當我們使用完畢後我們需要關閉輸入檔嗎? 我們如何指示某一個磁碟上的一 個檔案?
46
3.6 由檔案讀取資料 fscanf函數的動作。 (續下頁)
47
fscnaf(檔案指標,格式化字串,引數列 );
3.6 由檔案讀取資料 (續上頁) fscanf()函數的語法為 fscnaf(檔案指標,格式化字串,引數列 ); fscnaf()函數從檔案指標所指示的檔案中 依照格式化字串中的轉換指示讀取檔案的內 容。所讀取的內容被存放到引數列所給的 記憶體位址。
48
3.6 由檔案讀取資料 什麼是一個檔案指標?在目前而言,只需要 記住一個檔案指標是一個變數,它的記憶體
儲存格是用來存放位址,而不是int,float 或double型值。這個位址是取得磁碟中儲存 的檔案的關鍵。要宣告變數來儲存位址,也 就是檔案指標,我們的宣告必須以FILE開 始而且變數名稱前必須有一個星號 * 。
49
3.6 由檔案讀取資料 命名檔案指標的方式和命名C識別字相同。 合規定與不合規定的命名如下: 合規定:
FILE *apple , *IBM93 , *HP7475; 不合規定: FILE *+apple , *93IBM , *75HP75;
50
3.6 由檔案讀取資料 Fopen函數從程式碼中取得檔案名稱及模式然後建立一個位 址。
51
檔案指標 = fopen(檔案名稱,存取模式);
3.6 由檔案讀取資料 使用fopen建立連結的格式是 檔案指標 = fopen(檔案名稱,存取模式); 譬如說,在敘述 inptr=fopen("C3_6.IN", "r"); 中,作業系統所引用的檔案名稱(file_name) 是C3_6.IN,檔案指標是inptr,存取模式是 “ r ”,表示說這個檔案是以文字模式開啟來 供讀取的。
52
3.6 由檔案讀取資料 當你想要使用一個磁碟檔案時,你要使用C資料型 別FILE來宣告一個檔案指標,然後使用這個檔案
能使用敘述 FILE “L3_6.IN”; 來宣告你的檔 案。而是你必須使用FILE來宣告一個檔案指標, 然後使用檔案指標操作你的檔案。在過程上是 FILE --> 檔案指標 --> 實際檔案
53
3.6 由檔案讀取資料 我們如何指示某一個磁碟上的一個檔案? 譬如說,磁碟C:上的檔案C3_6.IN,我們可以用
敘述 inptr=fopen(“C: \\C3_6.IN”, “r”); 指示。注意到文字字串中的兩個反斜線是必要 的,在第二章中曾說過單一的反斜線有特別的意 義。所以我們在通常使用一個反斜線的地方使用 兩個反斜線是必須的。
54
3.7 數學庫存函數 課題: 使用標準數學引頭檔 double與float資料型別的對比 其它資料型別
55
3.7 數學庫存函數 我們如何看出double和float資料型別之間的差異? 在C中是否有其他的資料型別可用來儲存浮點數?
整數有不同的資料型別嗎? 我們常需要用到long int及unsigned long int嗎? 本課程式中的函數意義為何? 使用C數學庫存函數時該用哪一個引頭檔?
56
3.7 數學庫存函數 資料型別
57
3.7 數學庫存函數 整數資料型別
58
3.7 數學庫存函數 函數 (續下頁)
59
3.7 數學庫存函數 (續上頁) 更多的數學庫存函數
60
3.7 數學庫存函數 使用C數學庫存函數時該用哪一個引頭檔? 如要使用C庫存函數,你需要加入以下敘 述: #include<math.h>
或,在使用abs及fabs時,加入 #include<stdlib.h>
61
3.8 把輸出寫入檔案 課題: 寫資料到一個檔案 使用fprintf()函數
62
3.8 把輸出寫入檔案 我們用甚麼函數寫資料到一個檔案? 我們用甚麼函數來開啟一個輸出檔並在檔案及檔案指標之間建立連結?
我們需要關閉輸出檔嗎?
63
3.8 把輸出寫入檔案 我們用甚麼函數寫資料到一個檔案?在C中,我們 使用fprintf函數寫資料到一個檔案。一般而言
寫到和程式中的檔案指標相連結的檔案中。 (續下頁)
64
3.8 把輸出寫入檔案 (續上頁) fprintf函數的運作
65
檔案指標=fopen(檔案名稱,存取模式);
3.8 把輸出寫入檔案 在資料被寫到外部檔案外部之前,檔案必須用 fopen()函數開啟,它的語法是 檔案指標=fopen(檔案名稱,存取模式); 其中檔案指標及檔案名稱的定義和開啟輸入檔時相 同。但是寫入資料時的存取模式是“ w ”,表示檔案 是開啟來以文字模式寫入。 舉例來說,在敘述 myfile=fopen("L3_7.out" , "w");
66
3.9 單一字元資料 課題: 字元集 單一字元的輸入輸出 字元視作整數處理 字元輸入輸出函數 輸入緩衝區 傾瀉緩衝區
67
3.9 單一字元資料 在本課程程式中你該觀察的事項。 關鍵字char被用來宣告11個單一字元。
有些編譯器擁有一些ANSI C所沒有明載的函數。部分這些函數的資訊可在本程式中引用的檔案conio.h中找到。 (續下頁)
68
3.9 單一字元資料 第一部分 頭三個指定敘述中的單一字元有用單引號包圍起來。 %c被用來作為printf中單一字元的轉換指示。
(續上頁) 第一部分 頭三個指定敘述中的單一字元有用單引號包圍起來。 %c被用來作為printf中單一字元的轉換指示。 putchar函數(如同printf)可以被用來列印單一字元。 printf敘述的輸出和四個putchar敘述的輸出 完全相同。 (續下頁)
69
3.9 單一字元資料 第二部分 具有%c的scanf敘述讀取由鍵盤輸入的單一字元。 這個scanf敘述中的兩個%c轉換指示之間沒有間隔。
(續上頁) 第二部分 具有%c的scanf敘述讀取由鍵盤輸入的單一字元。 這個scanf敘述中的兩個%c轉換指示之間沒有間隔。 字串xp是由scanf敘述輸入並由putchar敘述 列出。 printf敘述中的字元變數使用了%d轉換 指示。輸出的是數值。 (續下頁)
70
3.9 單一字元資料 第三部分 getchar函數可讀取由鍵盤輸入的單一字元。呼叫getchar時,括號之間並沒有任何東西。
(續上頁) 第三部分 getchar函數可讀取由鍵盤輸入的單一字元。呼叫getchar時,括號之間並沒有任何東西。 我們可以在指定敘述的右邊使用getchar。 本節裡其中一個getchar呼叫並不是在指定敘述的右邊。 字串qk是使用getchar函數輸入並有putchar 函數列印出來。 (續下頁)
71
3.9 單一字元資料 第四部分 本節中使用了fflush函數。 fflush中的引數是識別字stdin。 宣告fflush的位置並不明顯。
(續上頁) 第四部分 本節中使用了fflush函數。 fflush中的引數是識別字stdin。 宣告fflush的位置並不明顯。 fflush是在由鍵盤讀取字元之前及之後被呼叫。 字串vs是使getchar函數輸入並由putchar函 數列印出來。 (續下頁)
72
3.9 單一字元資料 第五部分 並不在ANSI C標準裡的getche函數是採用我們呼叫getchar函數的方式(不使用引數 )呼叫。
(續上頁) 第五部分 並不在ANSI C標準裡的getche函數是採用我們呼叫getchar函數的方式(不使用引數 )呼叫。 本節中並沒有呼叫fflush函數。 本節中輸入並輸出了字串wq。 在輸入wq之後並沒有按歸位鍵。
73
3.9 單一字元資料 我們如何宣告字元變數? 我們如何使用這些字元變數寫一個指定敘述?
甚麼是一切完整的ANSI C字元常數列表?C如何處理這些字元常數? 為什麼脫離序列(如\n,\r)被包含在字元集中? 我們如何使用printf函數來列印字元? putchar函數是如何運作? putchar(32)是做甚麼的? (續下頁)
74
3.9 單一字元資料 所有的電腦都會putchar(32)使列印一個空格嗎? 列印單一字元時我們該用printf還是putchar呢?
(續上頁) 所有的電腦都會putchar(32)使列印一個空格嗎? 列印單一字元時我們該用printf還是putchar呢? 我們如何使用scanf函數由鍵盤讀取字元? getchar函數是做甚麼的呢? getchar函數是直接從鍵盤處取得字元的嗎? 甚麼是輸入緩衝區而它是如何與getchar一起運作的呢? 總結來說處理getchar函數時的困難 為何? (續下頁)
75
3.9 單一字元資料 這個問題我們能如何處理呢? 甚麼是stdin? 有其他方法可以避免getchar的問題嗎?
(續上頁) 這個問題我們能如何處理呢? 甚麼是stdin? 有其他方法可以避免getchar的問題嗎? 為什麼不忘了getchar而只使用scanf? 那scanf與數值輸入資料又如何? scanf與fscanf之間的關係為何? 為什麼我們在這裡講了這麼多關於scanf及fscanf的細節? 我們應該學習更多有關字元資料 嗎?
76
3.9 單一字元資料 我們如何使用這些字元變數寫一個指定敘述?要指 派一個字元常數給一個字元變數時,必須要用單引
號,‘ ’,把常數值封包起來。譬如說,指定敘述 c1='g' ; 把字元g指派給變數c1。 一個常犯的錯誤是在該使用單引號時使用了雙引號 “ ”。請不要犯這個錯誤。如要正確地處理單一字 元及字元函數,你必須使用單引號。
77
3.9 單一字元資料 ANSI C字元及其ASCII碼/值(數字) (續下頁)
78
3.9 單一字元資料 注意ANSIC標準並不支援所有的ASCII字元集。所 以,你會注意到給定的列表中並不包含字元如 ’ $ ’
(續上頁) 注意ANSIC標準並不支援所有的ASCII字元集。所 以,你會注意到給定的列表中並不包含字元如 ’ $ ’ 及 ’α’。這導致的後果是你的編譯器不一定能編譯 下列敘述 printf("The first Greek character is %c\n", 'α'); 超越ANSI C標準的編譯器可能正確的編譯器並執 行這個敘述。
79
3.9 單一字元資料 putchar(32)是做甚麼的?因為C在函數中使用字元的整數值,
可以看到,值為32的字元是空格,也就是說一個空格被列印到螢幕 上。所以printf敘述 printf("%c %c\n" , c1, c2); (在兩個%c轉換指示及\n之間有一個空格)和putchar敘述 putchar(c1); putchar(32); putchar(c2); putchar(c3); 完成相同的工作。
80
3.9 單一字元資料 所有的電腦都會putchar(32)使列印一個空 格嗎?不,只有使用ASCII編碼方法的電腦
(絕大部分是個人電腦)會把32解釋為空 格。為了使你的程式可在不同的電腦上使 用,我們建議你把putchar(32)換成 putchar(' ')。
81
3.9 單一字元資料 甚麼是輸入緩衝區而它是如何與getchar一起運作的呢?一 個緩衝區是一般記憶體用來暫時保存傳送的資訊。這些記
憶體的存取是採取序列式的,表示說記憶體是一個接著一 個(成序列)被讀取。一個位置指示器被用來追蹤沒有進 一步的資訊可供讀取的位置。在讀取一個儲存格的時候位 置指示器會前進一個儲存格使得下一個儲存格可被讀取。 getchar函數使用緩衝區的位置指示器來取得緩衝區中的下 一個字元並把位置指示器前移。當getchar函數被呼叫時, 它會讀取下一個儲存格的內容或者是(當下一個位址的 內容是空的)停止執行並等待。在這個時候可以輸 入一個或多個字元。在Enter鍵被按下後, getchar函數會被重新啟動。(續下頁)
82
3.9 單一字元資料 在本課程的程式中,首先被輸入的按鍵為 xp 也就是說緩衝區中為
(續上頁) 在本課程的程式中,首先被輸入的按鍵為 xp 也就是說緩衝區中為 1.敘述getchar( )被執行。程式由緩衝區讀取\n。這個敘述的目的,在讀取緩衝區中的一個儲存格之後,只不過是要把位置指示器向前前進。 (續下頁)
83
3.9 單一字元資料 (續上頁) 2.因為在緩衝區的位置指示器之後並沒有東西,敘述c6=getchar( );對getchar的呼叫導致執行停止並等待使用者的輸入。使用者鍵入vs使得緩衝區變成 3.接著敘述c6= getchar( );及c7= getchar( );被執行。 緩衝區以及位置指示器變成
84
3.9 單一字元資料 這個問題我們能如何處理呢?在獲得想要的 字元之後我們可以排去或清除緩衝區的內 容。這可以使用fflush函數達成。
清除輸入緩衝區的格式是 fflush(stdin);
85
3.9 單一字元資料 甚麼是stdin? stdin也是一個檔案指標。在 stdio.h中,stdin被定義為指向標準輸入資料
流。所以,fflush(stdin);會清除stdin所指向 的標準輸入資料流,也就是鍵盤的輸入緩衝 區。注意到,因為stdin在stdio.h中有定義, 在使用了stdio.h的程式中你不能使用stdin 作為一個變數的識別字。
86
3.9 單一字元資料 有其他方法可以避免getchar的問題嗎?雖然不是 ANSIC相容,但是getche函數可以在很多編譯器
中找到,尤其是給PC用的。這個函數並不使用輸 入緩衝區,所以會產生沒有緩衝的輸入。它直接 與作業系統打交道而且並不需要按下Enter來傳輸 字元碼。結果是單一的按鍵動作會被立刻的接收 到而且不需要用到輸入緩衝區。所以並不需要擔 心多餘的字元。清除緩衝區是不需要的。
87
3.9 單一字元資料 為什麼不忘了getchar而只使用scanf?當scanf函數被啟動
時,程式的執行中止。然後程式使用者鍵入資訊,該資訊 並傳輸到輸入緩衝區中。當使用者按下Enter鍵,程式恢復 執行並導致scanf讀取輸入緩衝區中的資訊。scanf函數把 文字字串(或格式化字串)中內容分為三類: 轉換或格式指定字(以一個%開始)。 空白字元(對scanf而言不光只是一個空格,scanf把跳格及Enter[換行 \n ]也視為空白)。 非空白字元。
88
3.9 單一字元資料 scanf與fscanf之間的關係為何?fscanf函數 的運作和scanf函數完全相同,只不過輸入
資料流不同(是指定的檔案而不是 stdin)。我們針對scanf所說的一切對fscanf 依然適用。
Similar presentations