Download presentation
Presentation is loading. Please wait.
1
鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
函式 鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
2
綱要 函式呼叫 傳值函式 傳址函式 out參數 陣列作為函式參數與傳回值 井字遊戲Tic-tac-toe函式版
3
函式 集中重複或類似的程式碼片段為一個函式 縮短簡化原程式,使程式較容易閱讀,也比較不會出錯
各函式的資料相互獨立,讓程式開發團隊成員可以同時各自撰寫偵錯不同函式,方便合作 下一章再介紹較複雜程式的規畫與函式導向的程式設計方法
4
綱要 函式呼叫 傳值函式 傳址函式 out參數 陣列作為函式參數與傳回值 井字遊戲Tic-tac-toe函式版
5
呼叫函式一例 Random rand = new Random(); int k = rand.Next() % 30 + 1;
for (int i = 0; i < k; ++i) { for (int j = 0; j < 50; ++j) Console.Write("*"); } Console.WriteLine();
6
函式呼叫流程 class Program { static void Main(string[] args)
int k = rand.Next() % ; } public class Random { . . . public int Next() } }
7
CallingFunctions.Program.Main static void Main(string[] args) {
Random rand = new Random(); int k = rand.Next() % ; for (int i = 0; i < k; ++i) PrintALineOfStars(); }
8
CallingFunctions.Program. PrintALineOfStars
static void PrintALineOfStars() { for (int j = 0; j < 50; ++j) Console.Write("*"); } Console.WriteLine();
9
函式呼叫流程 class Program { static void Main(string[] args) A(); . . . }
static void A() B(); static void B()
10
偵錯器的進一步應用 “逐步執行”與”不進入函式”的差別 目前類別與函式顯示 監看式的應用 呼叫堆疊的應用 即時運算視窗的應用
11
有回傳值的函式宣告與呼叫 static int ARandomNumber() { Random rand = new Random();
int result = rand.Next(); return result; } int k = ARandomNumber() % ;
12
產生多個亂數時的問題 int k1 = ARandomNumber(); int k2 = ARandomNumber();
13
函式名稱的商榷 動詞片語 名詞片語 宣告為void , 沒有回傳值 內容為執行一些動作 呼叫時可以呈現出一個祈使句的形式
例:PrintALineOfStars 名詞片語 描述傳回值的內涵 例:ARandomNumber
14
綱要 函式呼叫 傳值函式 傳址函式 out參數 陣列作為函式參數與傳回值 井字遊戲Tic-tac-toe函式版
15
數學函數 函數與自變數 sin(x), x = p/6, x = p/2 真實參數, 形式參數, 傳回值
16
數學函式呼叫流程 double y = Math.Sin( Math.PI/6 ); class Math {
static double Sin( double x ) . . . return result; }
17
傳值呼叫及以值回傳 形式參數 呼叫函式記憶區 區域變數 真實參數 結果變數 傳回值 形式參數 被呼叫函式記憶區 區域變數 傳回值
18
水平拋體計算 老鷹抓著石頭水平飛行 老鷹放開石頭攻擊地面目標 在主控台螢幕上看到石頭落下 水平方向的移動距離為 x = v0 t
垂直落下距離為 y = g t2/2
19
虛擬碼 1 Screen[0,0]~Screen[NY-1,NX-1]設為空白 2 for(t=0; t<NT; ++t) {
2.1 Screen[y, x] = ' ' 2.2 x = HorizontalDistance(v0, t) 2.3 y = VerticalDistance(g, t) 2.4 Screen[y, x] = 'o' 2.5 重新顯示Screen // 動畫效果 }
20
函式虛擬碼 HorizontalDistance( v0, t ) 1 x = v0*t 2 return x
21
函式虛擬碼 VerticalDistance( g, t ) 1 y = 0.5*g*t*t 2 return y
22
PlottingTrajectory.Program.Main 片段
for (t = 0; t < NT; ++t) { Screen[y, x] = ' '; x = HorizontalDistance(v0, t); y = VerticalDistance(g, t); if (x >= NX || y >= NY) break; Screen[y, x] = 'o'; Console.Clear(); for (i = 0; i < NY; ++i) { for (j = 0; j < NX; ++j) { Console.Write(Screen[i, j]); } Console.WriteLine();
23
PlottingTrajectory.Program. HorizontalDistance
static int HorizontalDistance(double v0, int t) { double x = v0 * t; return (int) x; }
24
PlottingTrajectory.Program. VerticalDistance
static int VerticalDistance(double g, int t) { double y = 0.5 * g * t * t; return (int) y; }
25
綱要 函式呼叫 傳值函式 傳址函式 out參數 陣列作為函式參數與傳回值 井字遊戲Tic-tac-toe函式版
26
SwappingIntegers.Program 片段
int x = 3; int y = 5; Swap(x, y); Debug.Assert(x == 5 && y == 3); . . . static void Swap(int x, int y) { int temp = x; x = y; y = temp; }
27
正確版本片段 int x = 3; int y = 5; Swap(ref x, ref y);
Debug.Assert(x == 5 && y == 3); . . . static void Swap(ref int x, ref int y) { int temp = x; x = y; y = temp; }
28
Euclid.Program.Main static void Main(string[] args) {
Debug.Assert(GCD( 1, 5 ) == 1); Debug.Assert(GCD( 12, 18 ) == 6); Debug.Assert(GCD(17, 13) == 1); Console.Write("輸入第一個正整數: "); int x = Convert.ToInt32(Console.ReadLine()); Console.Write("輸入第二個正整數: "); int y = Convert.ToInt32(Console.ReadLine()); Console.WriteLine("兩數的最大公因數為{0}", GCD(x, y)); }
29
Euclid.Program.GCD static int GCD(int x, int y) {
if (x < y) Swap(ref x, ref y); // x 較小時, 需交換x 與 y int remainder; while (y != 0) { remainder = x % y; x = y; y = remainder; } return x;
30
Euclid.Program.Swap static void Swap(ref int x, ref int y) {
int temp = x; x = y; y = temp; }
31
綱要 函式呼叫 傳值函式 傳址函式 out參數 陣列作為函式參數與傳回值 井字遊戲Tic-tac-toe函式版
32
應用傳址參數傳回多個變數值 同時以函式的多個計算結果來改變真實參數內容
閱讀程式時,不易區分使用傳址參數取得函式計算結果與利用傳址參數改變真實參數的兩種情況,不利了解與偵錯 需設定真實變數初值 改用out參數較佳 不必設定真實變數初值
33
UsingOutArguments.Program.Main static void Main(string[] args) {
int a = 5; int perimeter1 = 0; int area1 = 0; GetAreaAndPerimeterOfASquare( a, ref area1, ref perimeter1); Debug.Assert(area1 == 25 && perimeter1 == 20); int perimeter2; int area2; GetAreaAndPerimeterOfASquareUsingOut( a, out area2, out perimeter2); Debug.Assert(area2 == 25 && perimeter2 == 20); }
34
UsingOutArguments.Program. GetAreaAndPerimeterOfASquare
static void GetAreaAndPerimeterOfASquare( int a, ref int area, ref int perimeter) { area = a * a; perimeter = 4 * a; }
35
UsingOutArguments.Program. GetAreaAndPerimeterOfASquareUsingOut
static void GetAreaAndPerimeterOfASquareUsingOut( int a, out int area, out int perimeter) { area = a * a; perimeter = 4 * a; }
36
綱要 函式呼叫 傳值函式 傳址函式 out參數 陣列作為函式參數與傳回值 井字遊戲Tic-tac-toe函式版
37
一維陣列記憶配置 p[0] p p[1] p[2] p[3] p[4]
38
PassingArray.Program.Main片段
int[] p = { 1, 2, 3, 4, 5 }; int[] pCopy = p; PassArrayElementByValue(p[2]); PassArrayElementByReference(ref p[2]); PassArrayElementAsOutParameter(out p[2]); PassArrayByValue(p); Debug.Assert(p == pCopy); PassArrayByReference(ref p); Debug.Assert(p != pCopy); PassArrayAsOutParameter(out p);
39
陣列p和pCopy的參考指向相同位置 p pCopy
40
PassingArray.Program. PassArrayElementByValue
static void PassArrayElementByValue(int x) { x *= 2; }
41
PassingArray.Program. PassArrayElementByReference
static void PassArrayElementByReference(ref int x) { x *= 2; }
42
PassingArray.Program. PassArrayElementAsOutParameter
static void PassArrayElementAsOutParameter(out int x) { x = 3; }
43
PassingArray.Program. PassArrayByValue
static void PassArrayByValue(int[] a) { for (int i = 0; i < a.Length; ++i) a[i] *= 2; } a = new int[] { 7, 8, 9 };
44
PassingArray.Program. PassArrayByReference
static void PassArrayByReference(ref int[] a) { for (int i = 0; i < a.Length; ++i) a[i] *= 2; } a = new int[] { 7, 8, 9 };
45
PassingArray.Program. PassArrayAsOutParameter
static void PassArrayAsOutParameter(out int[] a) { a = new int[] { 1, 2, 3, 4, 5 }; }
46
使用重構修改Array2D 擷取方法 AverageOfEachRow 重新命名 table
47
ReturningArray.Program.Main片段
double[] individualAverage = AverageOfEachRow(score); double[] subjectAverage = AverageOfEachColumn(score); for (int i = 0; i < N_STUDENTS; ++i) { Console.WriteLine("{0}: 兩科平均成績 {1}", registerNumber[i], individualAverage[i]); } for (int j = 0; j < N_SUBJECTS; ++j) { Console.WriteLine("{0}: 全班平均成績 {1}", subject[j], subjectAverage[j]);
48
ReturningArray.Program. AverageOfEachRow
static double[] AverageOfEachRow(int[,] table) { int nRows = table.GetUpperBound(0)+1; double[] average = new double[nRows]; int nColumns = table.GetUpperBound(1)+1; for (int i = 0; i < nRows ; i++) { int sum = 0; for (int j = 0; j < nColumns; j++) { sum += table[i, j]; } average[i] = (double)sum / nColumns; return average;
49
以Random物件為參數 static int ARandomNumber( Random rand ) {
int result = rand.Next(); return result; } Random rand = new Random(); int k1 = ARandomNumber( rand ); int k2 = ARandomNumber( rand );
50
綱要 函式呼叫 傳值函式 傳址函式 out參數 陣列作為函式參數與傳回值 井字遊戲Tic-tac-toe函式版
51
判斷使用者或電腦獲勝虛擬碼 判斷使用者或電腦獲勝 Won( i0, j0, board ) 1 設使用者或電腦最新位置在i0, j0
2 檢查是否成列 if( board[i0, 0] == board[i0, 1] == board[i0, 2] ) return true 3 檢查是否成行 if( board[0, j0] == board[1, j0] == board[2, j0] ) return true 4 檢查主對角線是否均為'x' 或 'o' if( board[0, 0] == board[1, 1] == board[2, 2] == board[i0, j0] ) return true 5 檢查次對角線是否均為'x' 或 'o' if( board[0, 2] == board[1, 1] == board[2, 0] == board[i0, j0] ) 6 return false
52
亂數產生‘o’位置虛擬碼 虛擬碼: 亂數產生'o'位置 TakeAPosition( board, io, jo ) 0 | 1 | 2
3 | 4 | 5 6 | 7 | 8 1 do { 1.1 產生一個0到8的亂數k 1.2 io = k / 3 1.3 jo = k % 3 } while( board[io,jo] 不是空白 ) 2 board[io, jo] = 'o'
53
TicTacToe2.Program.Main片段
do { Display(board); Console.Write("輸入x位置的座標, 以逗點分隔: "); string[] input = new string[2]; input = Console.ReadLine().Split(','); int ix = Convert.ToInt16(input[0]); int jx = Convert.ToInt16(input[1]); board[ix, jx] = 'x'; userWin = Won(ix, jx, board); hasVacancies = HasVacancies(board); if (userWin || !hasVacancies) break;
54
TicTacToe2.Program.Main片段
TakeAPosition(rand, board, out io, out jo); computerWin = Won(io, jo, board); if (computerWin) break; hasVacancies = HasVacancies(board); } while (hasVacancies); Display(board); if (userWin) { Console.WriteLine("使用者獲勝"); } else if (computerWin) { Console.WriteLine("電腦獲勝"); } else { Console.WriteLine("平手");
55
TicTacToe2.Program.Won static bool Won(int i0, int j0, char[,] board) { if ((board[i0, 0] == board[i0, 1]) && (board[i0, 1] == board[i0, 2])) return true; if ((board[0, j0] == board[1, j0]) && (board[1, j0] == board[2, j0])) return true; if ((board[0, 0] == board[i0, j0]) && (board[1, 1] == board[i0, j0]) && (board[2, 2] == board[i0, j0])) return true; if ((board[0, 2] == board[i0, j0]) && (board[2, 0] == board[i0, j0])) return true; return false; }
56
TicTacToe2.Program.TakeAPosition
static void TakeAPosition(Random rand, char[,] board, out int io, out int jo) { do { int k = rand.Next() % 9; io = k / 3; jo = k % 3; } while (board[io, jo] != ' '); board[io, jo] = 'o'; }
57
TicTacToe2.Program.Display
static void Display(char[,] board) { Console.Clear(); Console.WriteLine(" "); Console.WriteLine(" "); Console.WriteLine("0 {0} | {1} | {2} ", board[0, 0], board[0, 1], board[0, 2]); Console.WriteLine(" "); Console.WriteLine("1 {0} | {1} | {2} ", board[1, 0], board[1, 1], board[1, 2]); Console.WriteLine("2 {0} | {1} | {2} ", board[2, 0], board[2, 1], board[2, 2]); }
58
TicTacToe2.Program.HasVacancies
static bool HasVacancies(char[,] board) { bool hasVacancies = false; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (board[i, j] == ' ') { hasVacancies = true; break; } return hasVacancies;
Similar presentations