500 likes | 608 Views
視窗程式設計. Class 2 教師:黃聖方. 第四章. 陣列與字串. 4-1 陣列. 陣列的宣告. 陣列的宣告與初始化範例. 4-2 Jagged Array. C# 另外提供一個建立特殊的二維陣列,陣列中的每一列的長度可以不相同,稱為「 Jagged Array 」。其語法如下: DataType [][] arrayname = new DataType[size][] ; 一般建立 Jagged Array 的方式如下: int [][] myjag = new int [3][] ;
E N D
視窗程式設計 Class 2 教師:黃聖方
第四章 陣列與字串
4-1 陣列 • 陣列的宣告
4-2 Jagged Array • C#另外提供一個建立特殊的二維陣列,陣列中的每一列的長度可以不相同,稱為「Jagged Array」。其語法如下: DataType [][] arrayname = new DataType[size][] ; • 一般建立Jagged Array的方式如下: • int [][] myjag = new int [3][] ; • myjag[1] = new int[2] ; • myjag[2] = new int[4] ; • myjag[0] = new int[3] ;
陣列方法 • 當變數宣告為陣列時便繼承了Array類別的一些方法,因此可以把也宣告為陣列變數當成物件一般來使用,並呼叫其方法。 • 相關方法可見VS中的提示說明。 • 注意,只有一維陣列才可以把陣列當成物件使用。
4-3 ArrayList類別 在 .NET Framework另外提供一個ArrayList類別,讓你可以建立不定長度的陣列,由於此種陣列的資料型別為Object,因此在陣列中的陣列元素允許存放任何型別的資料。 注意:ArrayList在System.Collections的命名空間之下
4-3 ArrayList類別 ArrayList成員表格
4-4 字元與字串 • 字串的宣告和初值設定 … string address ; string city = "台中市", street = "中興路一段" ; int no = 168 ; address = city + street +no ; // 台中市中興路一段168 address+="號"; // 將”號”加到address字串變數的後面 char char1="MIB戰警"[3]; //取得指定字串由0開始算起第3個字元 char char2=address[5]; //取得address字串由0開始算起第5個字元 … 註:這裡的字元是Unicode字元,不是byte;所以address[5]會回傳「興」。
4-4 字元與字串 • C# .NET字元類別成員 語法:char.Equals(objectA,objectB) ; 功能:若物件A與物件B相等則傳回true,否則傳回false 範例:bool result; char char1=’a’; char char2=’c’; result=char.Equals(char1,char2) ; // false Console.WriteLine(result.ToString()); //顯示False 註:字元常數用單引號刮起來。
4-4 字元與字串 • C# .NET字串類別成員 語法:str1.Equals(str2) ; 功能:檢查str1字串是否和str2字串相等 範例:if(str1.Equals(str2)) .... 與 if (str1==str2) .... 功能相同
第五章 方法的參數傳遞、程式偵錯與例外處理
5-1 方法 • 方法擁有自已的名稱,可以使用是合法的C# .NET識別字來命名。但其名稱不能和變數、常數或定義在類別內的屬性或其他方法名稱重複。 • 方法內所宣告的變數(即屬性)是屬於區域變數,也就是說C# .NET在不同方法內所宣告的變數彼此互不相關,其有效範圍侷限在該方法內。所以,在不同的方法內是允許使用相同區域變數名稱。 • 方法具有特定功能,程式碼簡單明確,可讀性高而且易除錯和維護。
5-1 方法(續) C# .NET所提供的方法依其特性可分成三大類: • 系統提供的方法 • 使用者自訂的方法 • 事件
5-2 如何定義方法 • 定義方法 1. 定義方法的語法如下: access代表呼叫的權限。 static代表的含意:此函式可不經由物件的建立來呼叫,透過直接撰寫類別來呼叫。
靜態方法使用須知 • 譬如說,你希望在主類別當中的Main方法以外,建立一個可供Main呼叫的方法CheckID,則因為Main為預設為靜態方法,那麼被Main呼叫的CheckID也必須宣告為static。 • 原因:靜態方法不需產生物件即可直接呼叫,其所呼叫的方法如果不是靜態的(必須建立物件才可呼叫),那麼不是與靜態的意義互相矛盾嗎?
5-2 如何定義方法(續) 2. 成員存取修飾功能說明如下表:
5-2 如何定義方法(續) • 如何呼叫方法 1.在C# .NET中呼叫使用者自訂靜態方法的語法有下列兩種方式:
5-2 如何定義方法(續) 2. 下圖即為同類別的方法呼叫:
5-2 如何定義方法(續) 3. 下圖即為不同類別的方法呼叫:
5-3 參數的傳遞方式 • 傳值呼叫 (Call by value) 在一個方法A呼叫另一個方法B時,方法A的實引數值會拷貝一份給方法B中所對應的虛引數,由於兩者的引數並不佔用相同的記憶位址,方法B在執行中所對應的參數若有改變時,並不會影響方法A中的參數值。
5-3 參數的傳遞方式(續) 【傳值呼叫_範例】 • // Filename: cs_CallValue.sln • 1. using System; • 2. namespace cs_CallValue • 3. { • 4. class Class1 • 5. { • 6. private static void CallValue(int x, int y) • 7. { • 8. int z; • 9. x=20; • 10. y=30; • 11. Console.WriteLine ("\n方法內 交換前 : x= {0} y={1} ",x,y); • 12. z=x; //透過第三個變數來做x,y值作互換 • 13. x=y; • 14. y=z; • 15. Console.WriteLine ("\n方法內 交換後 : x= {0} y={1} ",x,y); • } • 17. [STAThread] • 18. static void Main(string[] args) • 19. { • 20. Console.WriteLine("\n **** Call By Value 傳值呼叫 **** \n");
5-3 參數的傳遞方式(續) 【傳值呼叫_範例】 21. int a = 10 ; 22. int b = 12 ; 23. Console.WriteLine ("\n呼叫敘述 未進入方法前 : a= {0} b={1} ",a,b); 24. CallValue(a, b) ; 25. Console.WriteLine ("\n呼叫敘述 離開方法回原處時 : a= {0} b={1} ",a,b); 26. Console.ReadLine() ; 27. } 28. } 29. } 【結果】
5-3 參數的傳遞方式(續) • 參考呼叫 (Call by reference) 方法A呼叫方法B時,若希望將方法B的執行結果回傳給方法A,使用傳值呼叫是無法做到的。若能將實引數和虛引數彼此對應的參數設成佔用相同的記憶位址,此時虛引數一有改變,對應的實引數亦跟著改變,便可將方法B執行的結果回傳給方法A,此種方式稱為「參考呼叫」。
5-3 參數的傳遞方式(續) 【參考呼叫_範例】 // Filename: cs_CallRef.sln 1. using System; 2. namespace cs_CallRef 3. { 4. class Class1 5. { 6. private static void CallRef(ref int x, ref int y) 7. { 8. int z; 9. x=20; 10. y=30; 11. Console.WriteLine ("\n方法內 交換前 : x= {0} y={1} ",x,y); 12. z=x; //透過第三個變數來做x,y值作互換 13. x=y; 14. y=z; 15. Console.WriteLine ("\n方法內 交換後 : x= {0} y={1} ",x,y); 16. } 17. [STAThread] 18. static void Main(string[] args) 19. { 20. Console.WriteLine("\n **** Call By Reference 參考呼叫 **** \n");
5-3 參數的傳遞方式(續) 【參考呼叫_範例】 21. int a = 10 ; 22. int b = 12 ; 23. Console.WriteLine ("\n呼叫敘述 未進入方法前 : a= {0} b={1} ",a,b); 24. CallRef(ref a, ref b) ; 25. Console.WriteLine ("\n呼叫敘述 離開方法回原處 : a= {0} b={1} ",a,b); 26. Console.ReadLine() ; 27. } 28. } 29. } 【結果】
5-3 參數的傳遞方式(續) • 傳出參數 (Output parameter) 傳出參數與參考呼叫的實引數和虛引數都是共同佔用相同的記憶位址。兩者間主要差異在於傳出參數的實引數變數不必設定初值即可作參數傳遞,而參考參數必須先設定初值才能傳遞參數。若在「呼叫敘述」及「被呼叫方法」的引數串列的參數前面有加上out,即變為傳出參數。 註:因為C#強烈要求設計師對使用中的變數給初值;有些參考參數內的值本來就是要在呼叫函數中給,所以一開始給初值的話就很沒有意義,因為設定out的話,這樣的參數就可以不用給初值。
5-3 參數的傳遞方式(續) 【傳出參數_範例】 // Filename:cs_CallOut.sln 1. using System; 2. namespace cs_CallOut 3. { 4. class Class1 5. { 6. private static void CallOut(out int x, out int y) 7. { 8. int z; 9. x=20; 10. y=30; 11. Console.WriteLine ("\n方法內 交換前 : x= {0} y={1} ",x,y); 12. z=x; 13. x=y; 14. y=z; 15. Console.WriteLine ("\n方法內 交換後 : x= {0} y={1} ",x,y); 16. } 17. [STAThread] 18. static void Main(string[] args) 19. { 20. Console.WriteLine("\n **** Call Out 傳出參數 **** \n");
5-3 參數的傳遞方式(續) 【傳出參數_範例】 21. int a,b ; 22. Console.WriteLine ("\n呼叫敘述 未進入方法前 a 和 b 未設定初值 "); 23. CallOut(out a, out b) ; 24. Console.WriteLine ("\n呼叫敘述 離開方法回主程式 : a= {0} b={1} ",a,b); 25. Console.ReadLine() ; 26. } 27. } 28. } 【結果】
5-4 如何在方法間傳遞陣列資料 欲將整個陣列透過呼叫敘述的實引數,將整個陣列傳給被呼叫方法的虛引數,就必須使用參考呼叫。 【陣列傳遞_範例】 // Filename :cs_sendArray1.sln 1. using System; 2. namespace cs_sendArray 3. { 4. class Class1 5. { 6. private static int Max(ref int[] number) 7. { 8. int max = number[0] ; 9. int tot = number.Length ; 10. for (int i=0 ; i<tot ; i++) 11. { 12. if (number[i] > max) 13. max = number[i] ; 14. } 15. return max ;
5-4 如何在方法間傳遞陣列資料(續) 【陣列傳遞_範例】 16. } 17. static void Main(string[] args) 18. { 19. int[] num = new int[6] {-103, 190, 0, 32, -56, 100} ; 20. int high = num.Length ; 21. for (int i=0 ; i<high ; i++) 22. Console.WriteLine (num[i] ) ; 23. int max_num = Max(ref num) ; //呼叫Max方法,由陣列中找出最大值 24. Console.WriteLine ("最大數=" + max_num.ToString()) ; 25. Console.ReadLine() ; 26. } 27. } 28. } 【結果】
5-5 遞迴方法 在方法內的主體(Body)內含有一條敘述可以直接或間接呼叫自己本身,我們稱為「遞迴方法」(Recursive Method)。 【使用遞迴求出階層】 public static long factorial(int n) { if (n == 0) return 1 ; return (n * factorial(n-1)) ; }
5-6 覆寫方法(Overloading) 覆寫方法(Overloading)是指程式中允許一個方法擁有多個不同的定義,也就是說它可建立多個同名稱但引數不同的方法,以方便使用者減少方法命名的困擾以及增加程式設計的彈性。 【覆寫方法_範例】 public static int max(int a, int b){ …… } public static double max(double a , double b , double c) { …… } [STAThread] static void Main(string[] args) { int x = 6, y = 8 ; double i = 2.33, j = 1.55, k = 7.55 ; Console.WriteLine ("最大數=" + max(x, y).ToString() ) ; Console.WriteLine ("最大數=" + max(i, j, k).ToString()) ;} ……
5-7區塊變數、區域變數、靜態變數與屬性成員 • 區塊變數(block level variables) 區塊變數被定義在某個區塊中,可以是for、switch敘述區塊中所宣告的變數。例如在某個區塊中所宣告的變數,只能在這個區塊中使用 。 【區塊變數_範例】 class Class1 { static void Main(string[] args) { for(int i=1 ; i<=6 ; i++) //區塊變數 { Console.WriteLine(i) ; } Console.WriteLine(i) ; } }
5-7區塊變數、區域變數、靜態變數與屬性成員(續)5-7區塊變數、區域變數、靜態變數與屬性成員(續) 二. 區域變數(local variables) 區域變數是在方法(函式)中區塊外宣告的變數,或是方法的參數,區域變數一離開方法,其生命週期即馬上結束。 【區域變數_範例】 class Class1 { private void MyMethod(string str) { string name = “蔡小龍”; //區域變數 name += str ; //區域變數 int k ; //區域變數 for(int i=1 ; i<=6 ; i++) //區塊變數 Console.WriteLine(i) ; Console.WriteLine(i) ; } }
5-7區塊變數、區域變數、靜態變數與屬性成員(續)5-7區塊變數、區域變數、靜態變數與屬性成員(續) 三. 靜態變數(static variables) 若在「類別」內所宣告的變數(即屬性)前面若加上static,則此變數在類別內變成「靜態變數」(或稱靜態屬性)。靜態變數不能在方法內宣告,該變數的「生命週期」是到程式停止執行為止。右表為各種資料型別的預設初值。
5-7區塊變數、區域變數、靜態變數與屬性成員(續)5-7區塊變數、區域變數、靜態變數與屬性成員(續) 【靜態變數_範例】 • //FileName:cs_staticVar.sln • 1. using System; • 2. namespace cs_staticVar • 3. { • 4. class Class1 • 5. { • 6. private static int age = 25; • 7. private static string name = "王志明"; • 8. [STAThread] • 9. static void Main(string[] args) • 10. { • Console.WriteLine("Class1類別靜態變數的資訊-->{0}的年齡為{1}歲\n",name, age.ToString()); • //印出Class1類別靜態變數的資訊-->王志明的年齡為25歲 • Console.WriteLine("Class2類別靜態變數的資訊-->{0}的年齡無法取得",Class2.name); • //印出Class2類別靜態變數的資訊-->陳春嬌的年齡無法取得 • 13. Console.ReadLine(); • 14. } • 15. } • 16. class Class2 • 17. { • 18. private static int age = 29; • 19. public static string name = "陳春嬌";}}
5-7區塊變數、區域變數、靜態變數與屬性成員(續)5-7區塊變數、區域變數、靜態變數與屬性成員(續) 四. 物件屬性(非靜態成員) 物件屬性和靜態變數(有加上static修飾詞,或稱為靜態成員)一樣,不同的是因為物件屬性是放在Heap區,靜態變數是放在全域變數區,因此物件屬性必需建立該物件實體(執行個體)才能使用。當物件生命週期結束之後,非靜態的物件屬性生命週期就會跟著結束。 【物件屬性_範例】 class MyClass { public static int vNo ; //靜態變數,或稱靜態成員 public string vName ; //物件屬性 …… …… }
5-8 程式偵錯 撰寫程式時,常會碰到語法錯誤、邏輯錯誤或執行時期(run time)錯誤,可藉用Visual Studio .NET所提供的偵錯(Debug)工具,一步步逐行有耐心去觀察每行的結果找出不正確之處。至於執行時期錯誤,則可使用例外處理技巧。現介紹撰寫程式時常會遇到的上述三種錯誤(Bug): • 語法錯誤 • 執行時期錯誤 • 邏輯錯誤
程式偵錯 2. 選擇用Debug模式執行 1. 用滑鼠點選break point 3. 用自動變數視窗監看變數內容 在偵錯模式,點選偵錯->視窗->自動變數
5-9 例外處理 當程式在執行時期發生錯誤或不正常狀況,稱之為例外(Exception)。C#的例外處理是採用C++和Java的方式並加以改良,讓設計者能夠使用具結構化和易控制的方式來處理執行時期所發生的錯誤,找出其發生原因,再尋求解決方法。 一. try…catch…finally語法 try{ try statements; //受監視的程式碼 } catch (exception1 e){ catchStatements ; } catch (exception2 e){ catchStatements ; } finally{ finallyStatements; //最後執行的程式碼} 例如,可以寫一些程式碼以回復錯誤發生前的變數內容)
5-9 例外處理(續) 二. Exception類別 C# 的Exceptions是以類別來表示之,所有的例外類別都衍生自內建的Exception例外類別,此類別亦是System命名空間的一部分。下表列出衍生自System.Exception內建例外幾個常用的Exception類別:
5-9 例外處理(續) 三. Exception類別的成員
5-9 例外處理(續) 【例外處理_範例】 int a, b, c = 0 ; Console.Write("a = ") ; a = Int32.Parse(Console.ReadLine()) ; Console.Write("b = ") ; b = Int32.Parse(Console.ReadLine()) ; try{ c = a / b ;} catch (Exception e){ Console.WriteLine(e) ;} Console.WriteLine("c = " + c ) ; Console.Read() ; …… 【結果】
5-9 例外處理(續) • 自訂例外處理-使用throw敘述 遇到特殊錯誤,系統並沒有提供此種判斷,自己也可以寫程式來處理特殊錯誤,throw敘述即可指定用到那個例外類別,當然自己也可以定義的例外類別。 【丢出例外_範例】 private static void KeyinMonth(out int month){ Console.Write("輸入月份 ( 1 - 12 ) : ") ; month = int.Parse(Console.ReadLine()) ; if (month < 1 || month > 12) throw new ArgumentOutOfRangeException() ;} [STAThread] static void Main(string[] args){ try{ KeyinMonth(out month) ;} catch (ArgumentOutOfRangeException e){ Console.WriteLine("不合理月份\n") ;} catch (Exception e){ Console.WriteLine("其他種錯誤\n") ;} } …… ……
5-10 DateTime、Math及Random類別 • DateTime類別 .NET Framework類別庫中的DateTime類別可用來設定日期與時間。以下範例中dateTime1是使用DateTime類別所建立的日期時間物件實體,此日期時間物件為西元2002年1月23日上午4時5分6秒7毫秒。 • 幾個有關DateTime好用的方法 • 將字串轉換成時間: • Parse(String s) --- 將字串yyyy/mm/dd轉成時間型別 • ToShortDateString() --- 去除時間,保留日期轉成字串型別 • Day() --- 回傳日期中該月份的天數(可以用來檢查日期是否有超過該月分的正常天數) • DayOfWeek() --- 回傳該日期是禮拜幾 (星期天為0, 星期一為1…) DateTime dateTime1 = new DateTime(2002,1,23,4,5,6,7);
5-10 DateTime、Math及Random類別(續) 二. Math類別 .NET Framework類別庫中的Math(數學)類別,提供許多有關三角函數、對數以及其他常見的數學函數與常數。
5-10 DateTime、Math及Random類別(續) 三. Random(亂數)類別 在 .NET Framework類別中庫提供了Random類別,此類別為System.Random型別,其功能可用來產生亂數。使用Random類別中的方法時,必需建立Random物件實體才可使用。以下範例中rnd1是使用Random類別所建立的亂數物件實體。 Random類別沒有屬性,此類別常用的方法說明如下表: Random rnd1 = new Random() ;
5-10 DateTime、Math及Random類別(續) 【產生1到42之間不重複的亂數,模擬樂透彩開獎情形 _範例】 //FileName:cs_Random.sln 1. using System; 2. namespace cs_Random 3. { 4. class Class1 5. { 6. [STAThread] 7. static void Main(string[] args) 8. { 9. //建立num陣列,num[0]~num[7]預設值為0 10. int[] num = new int[8]; 11. Random rnd = new Random(); //建立亂數物件 12. int getData; 13. bool reapeatData ; 14. int tot = 1; 15. do 16. { 17. getData = rnd.Next(1,43); 18. reapeatData = false; 19. for (int i=1; i<=tot ; i++) 20. { 21. if(getData == num[i])
5-10 DateTime、Math及Random類別(續) 22. { 23. reapeatData = true; 24. break; 25. } 26. } 27. if (reapeatData == false) 28. { 29. num[tot] = getData; 30. tot++; 31. } 32. }while(tot < 8); 33. Console.WriteLine("本期樂透彩開獎號碼如下:"); 34. for (int j=1 ; j<num.Length-1; j++) 35. Console.WriteLine(" 第{0}個號碼:{1}",j.ToString(), num[j].ToString()); 36. Console.WriteLine("特別號號碼:{0}", num[7].ToString()); 37. Console.ReadLine();}}} 【結果】