《C#面向?qū)ο蟪绦蛟O(shè)計(jì)》第4章:數(shù)組與方法.ppt
第4章 數(shù)組與方法,主要內(nèi)容與學(xué)習(xí)目標(biāo) 4.1 數(shù)組 4.2 多維數(shù)組 4.3 值類型與引用類型 4.4 方法,主要內(nèi)容與學(xué)習(xí)目標(biāo),主要內(nèi)容: (1)聲明數(shù)組、創(chuàng)建對(duì)象數(shù)組、數(shù)組元素的引用。 (2)數(shù)組的Length屬性。 (3)數(shù)組初始化。 (4)可變長度的數(shù)組的聲明。 (5)foreach語句。 (6)數(shù)組對(duì)象的賦值運(yùn)算。 (7)多維數(shù)組的聲明和創(chuàng)建、多維數(shù)組初始化。 (8)二維數(shù)組應(yīng)用舉例。 (9)值類型與引用類型。 (10)方法。 (11)傳值方式、以傳值方式傳遞值類型參數(shù)、以傳值方式傳遞引用類型參數(shù)。 (12)傳引用方式、以傳引用方式傳遞值類型參數(shù)、以傳引用方式傳遞引用類型參數(shù)。 (13)值傳遞方式與引用傳遞方式比較。 學(xué)習(xí)目標(biāo): (1)使用方法,以模塊方式構(gòu)造程序。 (2)理解在方法之間傳遞信息的機(jī)制。 (3)理解如何聲明數(shù)組、初始化數(shù)組,以及引用數(shù)組的單獨(dú)元素。 (4)聲明和操縱多下標(biāo)數(shù)組。,4.1 數(shù)組,數(shù)組是同一類型的一組變量,數(shù)組允許你通過同一名稱引用這一系列的變量,并使用一個(gè)稱為“索引”或“下標(biāo)”的數(shù)字來進(jìn)行區(qū)分。數(shù)組中包含的變量(又稱數(shù)組的元素)具有相同的類型,該類型稱為數(shù)組的元素類型。 如果程序中要存儲(chǔ)一個(gè)月中每一天的日常開銷,可以創(chuàng)建一個(gè)含有 30 個(gè)元素的數(shù)組,而不必聲明30個(gè)變量。數(shù)組中的每個(gè)元素都存有一個(gè)值,可通過指定元素的索引進(jìn)行訪問。 例如,如果要用數(shù)組number表示5個(gè)整數(shù)的集合(26, 86, 98, 12, 68),可以這樣創(chuàng)建數(shù)組number: int number = new int5; 任務(wù)4.1:計(jì)算月平均降雨量 問題描述:編寫程序,從輸入對(duì)話框中輸入12個(gè)月中每個(gè)月的實(shí)際降雨量,計(jì)算月平均降雨量及月實(shí)際降雨量與月平均降雨量的偏差。并將結(jié)果輸出。 4.1.1 數(shù)組初始化 4.1.2 可變長度的數(shù)組的聲明,4.1.1 數(shù)組初始化,C#通過將初始值括在大括號(hào)()內(nèi),為在聲明時(shí)初始化數(shù)組提供了簡單而直接了當(dāng)?shù)姆椒?。特別要注意的是,如果聲明時(shí)未初始化數(shù)組,則數(shù)組成員自動(dòng)初始化為該數(shù)組類型的默認(rèn)初始值。 任務(wù)4.2:顯示月名稱 問題描述:修改計(jì)算月平均降雨量的程序,使命令窗口中的輸入提示是“一月”而不是“1月”,如圖4.3所示。,圖4.3 從命令窗口中輸入值,4.1.2 可變長度的數(shù)組的聲明,在前面的例子中,我們利用常數(shù)指定數(shù)組的大小,例如下面的語句中的常數(shù)12: double difference = new double12; 利用常數(shù)聲明數(shù)組大小不總占用有效的存儲(chǔ)空間。例如,假設(shè)我們聲明大小為100的整數(shù)數(shù)組: int numbers = new int100; 我們把利用常數(shù)聲明數(shù)組稱為“定長數(shù)組聲明”。利用定長數(shù)組聲明可能產(chǎn)生兩個(gè)問題:第1個(gè)問題是程序最多處理100個(gè)數(shù),如果我們需要處理的數(shù)多于100(例如,需要處理101個(gè)數(shù)),則必須修改程序后重新編譯,第2個(gè)問題是可能產(chǎn)生未充分利用空間的問題,上面的聲明語句分配100個(gè)空間而忽略這些空間是否被使用。假設(shè)程序平均處理20個(gè)數(shù),那么該程序的平均空間利用率只有20%。C#并不限于定長數(shù)組聲明,還可以在每次運(yùn)行程序時(shí)聲明不同長度的數(shù)組。下面的代碼提示用戶輸入數(shù)組的長度,然后創(chuàng)建指定長度的數(shù)組: int size; Console.WriteLine("請(qǐng)輸入要?jiǎng)?chuàng)建的數(shù)組的元素的個(gè)數(shù):"); size = Int32.Parse(Console.ReadLine(); numbers = new intsize; 任務(wù)4.3:創(chuàng)建數(shù)組 問題描述:在創(chuàng)建數(shù)組時(shí),元素個(gè)數(shù)是否能為變量。數(shù)組的Length屬性。 編寫一控制臺(tái)應(yīng)用程序,先輸入要?jiǎng)?chuàng)建的數(shù)組的元素的個(gè)數(shù),然后輸入每個(gè)元素的值,最后將數(shù)組輸出(如圖4.4所示)。,圖4.4 創(chuàng)建數(shù)組,4.2 多維數(shù)組,4.2.1 多維數(shù)組的聲明和創(chuàng)建 4.2.2 多維數(shù)組初始化 4.2.3 二維數(shù)組應(yīng)用舉例,4.2.1 多維數(shù)組的聲明和創(chuàng)建,除一維數(shù)組之外,C#還支持多維數(shù)組。一維數(shù)組由排列在一行中的所有元素組成,它只有一個(gè)索引。從概念上講,二維數(shù)組就像一個(gè)具有行和列的表格一樣??紤]以下考試成績的表格(表4.1),它有5行2列,5行代表5個(gè)學(xué)生,2列代表2次考試,第1列代表第1次考試的成績,第2列代表第2次考試的成績。 我們可以用一個(gè)二維數(shù)組表示這個(gè)表。先聲明并創(chuàng)建一個(gè)二維數(shù)組Score: int, Score = new int5, 2; 其中5表示行數(shù),2表示列數(shù)。二維數(shù)組有兩個(gè)索引(索引號(hào)從0開始),其中一個(gè)表示行,一個(gè)表示列,如我們要將第1行第2列的元素賦值為88,表示為: Score0, 1 = 88; Score 0, 1表示學(xué)生1的考試2成績,Score0, 0表示學(xué)生1的考試1成績。,表4.1 學(xué)生考試成績表,4.2.2 多維數(shù)組初始化,可以在聲明數(shù)組時(shí)將其初始化,如下所示: int, myArray = new int, 1,2, 3,4, 5,6, 7,8; 如果在聲明數(shù)組時(shí)提供了初始值設(shè)定項(xiàng),可省略 new 語句: int, myArray = 1,2, 3,4, 5,6, 7,8; 如果要聲明一個(gè)數(shù)組變量但不將其初始化,必須使用 new 運(yùn)算符將數(shù)組分配給此變量,例如: int, myArray; myArray = new int, 1,2, 3,4, 5,6, 7,8; / 正確 myArray = 1,2, 3,4, 5,6, 7,8; / 錯(cuò)誤 可以給數(shù)組元素賦值,例如: myArray2, 1 = 25; 也可以讀取數(shù)組元素的值,例如: int aNumber = myArray10, 1;,4.2.3 二維數(shù)組應(yīng)用舉例,任務(wù)4.4:二維數(shù)組 主要知識(shí)點(diǎn):二維數(shù)組的聲明、創(chuàng)建、初始化。輸出二維數(shù)組每個(gè)元素的值。將初始化的數(shù)組作為參數(shù)傳遞給方法。獲得數(shù)組每維的長度。 問題描述:創(chuàng)建一簡單程序,演示二維數(shù)組的聲明、創(chuàng)建、初始化,并將創(chuàng)建的數(shù)組對(duì)象以調(diào)用輸出數(shù)組的方法輸出。 任務(wù)4.5:學(xué)生考試成績統(tǒng)計(jì) 主要知識(shí)點(diǎn): 二維數(shù)組的應(yīng)用。 問題描述:假定5個(gè)學(xué)生參加了兩門課的考試,試統(tǒng)計(jì)出全部學(xué)生的最高分和全部學(xué)生的最低分及每個(gè)學(xué)生的平均成績,并輸出(如圖4.6所示)。,圖4.6 成績統(tǒng)計(jì),4.3 值類型與引用類型,前面講的基本數(shù)據(jù)類型都是值類型,到目前為止學(xué)過的數(shù)組、String、類是引用類型。如果某個(gè)數(shù)據(jù)類型在自己的內(nèi)存分配中包含數(shù)據(jù),則該數(shù)據(jù)類型是“值類型”?!耙妙愋汀焙兄赶虬瑪?shù)據(jù)的其他內(nèi)存位置的地址。也就是說,值類型變量的值是該變量包含的實(shí)際數(shù)據(jù),該實(shí)際數(shù)據(jù)存儲(chǔ)在值類型變量的存儲(chǔ)位置中。引用類型變量的值為一地址,該變量包含的數(shù)據(jù)存儲(chǔ)在該地址指向的內(nèi)存位置中。 下面我們介紹把一個(gè)變量的值賦給另外一個(gè)變量時(shí)發(fā)生的情況,考慮下列使用整數(shù)的賦值語句: int num1, num2; num1 = 14; num2 = num1; num1 += 5; 其中,變量聲明語句int num1, num2;分配了存儲(chǔ)了一個(gè)類型為int的值的存儲(chǔ)位置,同時(shí)命名這個(gè)位置為num1;分配了存儲(chǔ)了一個(gè)類型為int的值的另一個(gè)存儲(chǔ)位置,同時(shí)命名這個(gè)位置為num2(如圖4.7所示)。 為了在存儲(chǔ)位置為num1的存儲(chǔ)位置存儲(chǔ)一個(gè)整數(shù)值,即把一個(gè)整數(shù)值賦給變量num1,我們寫出的語句為: num1 = 14; 圖4.8說明了此賦值語句執(zhí)行之后內(nèi)存的狀態(tài)。 為了在存儲(chǔ)位置為num2的地方存儲(chǔ)一個(gè)與存儲(chǔ)位置為num1的地方所存儲(chǔ)的值同樣的整數(shù)值,即把num1變量的值賦給變量num2,我們寫出的語句為: num2 = num1; 圖4.9說明此賦值語句執(zhí)行之后內(nèi)存的狀態(tài)。 執(zhí)行語句“num1+=5;”后內(nèi)存的狀態(tài)如圖4.10所示。,圖4.7 聲明整型變量的結(jié)果,圖4.8 整型變量賦值的結(jié)果一,圖4.9 整型變量賦值的結(jié)果二,圖4.10 整型變量賦值的結(jié)果三,4.4 方法,方法是用來實(shí)現(xiàn)可以由對(duì)象或類執(zhí)行的計(jì)算或操作。 在前面幾章中,我們已經(jīng)嘗試過如何在自己定義的類中定義自己的Main方法,也定義過事件處理方法,用它們指定我們?cè)诔绦蛑邪l(fā)生的操作,在我們的方法中調(diào)用.NET框架類庫(FCL)中的一些類的方法以執(zhí)行特定的任務(wù),如MessageBox類的Show方法、Int32類的Parse方法、Math類的Pow方法等。 應(yīng)用程序中的每行代碼都必須在某個(gè)方法的內(nèi)部,如Main、Calculate或button1_Click。 可以把在一個(gè)程序中多次用到的某個(gè)任務(wù)定義為方法,如常用的計(jì)算、文本和控件的操作。方法對(duì)執(zhí)行重復(fù)或共享的任務(wù)很有用,可以在代碼中的許多不同位置調(diào)用方法,因此可以將方法作為應(yīng)用程序的生成塊。 用方法構(gòu)造代碼有以下優(yōu)點(diǎn): 方法允許將程序分為不連續(xù)的邏輯單元。調(diào)試單獨(dú)的單元與調(diào)試不包含方法的整個(gè)程序相比要容易得多。 可以在其他程序中使用為某個(gè)程序開發(fā)的方法,而通常只需進(jìn)行少量修改,甚至不需要修改。 4.4.1 傳值方式 4.4.2 以傳值方式傳遞值類型參數(shù) 4.4.3 以傳值方式傳遞引用類型參數(shù) 4.4.4 傳引用方式 4.4.5 以傳引用方式傳遞值類型參數(shù) 4.4.6 以傳引用方式傳遞引用類型參數(shù),4.4.1 傳值方式,如果聲明方法的參數(shù)時(shí),參數(shù)前沒有ref或out修飾符,則調(diào)用方法時(shí),以傳值方式向方法傳遞參數(shù)。在C#中默認(rèn)為通過值傳遞參數(shù)。 所謂“傳值”,就是在方法調(diào)用時(shí),將實(shí)參的值傳遞給形參。如果實(shí)參的類型為值類型,則實(shí)參的值為該參數(shù)包含的數(shù)據(jù)。如果實(shí)參的類型為引用類型,則實(shí)參的值為地址。 如參數(shù)是以傳值方式傳遞,形參將創(chuàng)建新的存儲(chǔ)位置,在該存儲(chǔ)位置存儲(chǔ)形參接收的值。也就是說,被調(diào)用的方法將接收實(shí)參的一個(gè)副本。傳值時(shí),如果對(duì)被調(diào)用的方法的值的副本進(jìn)行修改(也就是形參的值進(jìn)行修改),不會(huì)影響實(shí)參變量的值。也就是說,傳值時(shí),允許在方法體內(nèi)將新值賦給形參。這樣的賦值只影響由形參表示的局部存儲(chǔ)位置的值它們不影響在方法調(diào)用中給出的實(shí)參的值,這是因?yàn)閰?shù)以傳值方式傳遞時(shí),形參和實(shí)參的存儲(chǔ)位置不同。以傳值方式時(shí),形參的初始化是通過復(fù)制對(duì)應(yīng)實(shí)參的值來完成的。 在這里我們?cè)俳o出一個(gè)概念:值參數(shù)。值參數(shù)以傳值方式進(jìn)行傳遞。注意,不要將值參數(shù)和值類型參數(shù)弄混淆。值參數(shù)既可是值類型參數(shù)也可以是引用類型參數(shù)。 值參數(shù)在調(diào)用方法時(shí)出現(xiàn),并由調(diào)用中給定的參數(shù)值初始化。值參數(shù)也是局部變量,它和局部變量一樣,當(dāng)所在方法返回時(shí)消失。,4.4.2 以傳值方式傳遞值類型參數(shù),值類型參數(shù)的值為該參數(shù)包含的實(shí)際數(shù)據(jù),以傳值方式傳遞值類型參數(shù)時(shí),當(dāng)形參接收到實(shí)參的值后,形參變量和實(shí)參變量就不再有任何關(guān)系。 任務(wù)4.6:移動(dòng)矩形 問題描述:創(chuàng)建一個(gè)Rectangle類來描述矩形,矩形有兩個(gè)基本屬性即位置和大小。并定義一個(gè)方法,將矩形的位置調(diào)整指定的量。,4.4.3 以傳值方式傳遞引用類型參數(shù),引用類型參數(shù)的值是地址,該地址表示的存儲(chǔ)位置存儲(chǔ)的是該引用類型變量引用的對(duì)象。以傳值方式傳遞引用類型參數(shù)時(shí),形參分配獨(dú)立的存儲(chǔ)位置,該存儲(chǔ)位置與實(shí)參的存儲(chǔ)位置不同。形參接收到的值為一地址并將其存儲(chǔ)在形參表示的存儲(chǔ)位置中,形參所引用的對(duì)象存儲(chǔ)在形參的值表示的存儲(chǔ)位置中。 因此,以傳值方式傳遞引用類型參數(shù)時(shí),將創(chuàng)建實(shí)參值(地址)的副本,而不是實(shí)參引用對(duì)象的副本。 數(shù)組是引用類型,數(shù)組變量的值是一地址,該地址表示的存儲(chǔ)位置存儲(chǔ)的是該數(shù)組變量所引用的數(shù)組對(duì)象。 要向方法傳遞一個(gè)數(shù)組參數(shù),需要在省略括號(hào)的前提下指定數(shù)組名。如任務(wù)4.1中調(diào)用printArray方法采用如下方式: printArray(app.rainfall); 任務(wù)4.7:以傳值方式傳遞數(shù)組 主要知識(shí)點(diǎn): 通過傳值方式傳遞引用類型變量。 下面的例子使用任務(wù)4.1中的代碼,修改printArray方法。該例子演示:向printArray方法傳遞引用類型的參數(shù)app.rainfall。由于該參數(shù)是對(duì)app.rainfall數(shù)組對(duì)象的引用,所以printArray方法有可能更改數(shù)組元素的值。但是,將形式參數(shù)aArray重新分配到不同的內(nèi)存位置時(shí),該操作僅在方法內(nèi)有效,并不影響原始變量app.rainfall。 解決方案: (1)打開任務(wù)4.1的項(xiàng)目,然后打開其代碼文件。將MonthActualApp類的printArray方法修改如下(修改處見帶底紋部分): (2)按Ctrl+F5鍵運(yùn)行該應(yīng)用程序,仍然按圖4.1所示輸入數(shù)據(jù),可得到如圖4.19所示的輸出。 (3)再次將printArray方法修改如下(修改處見帶底紋部分): (4)按Ctrl+F5鍵運(yùn)行該應(yīng)用程序,仍然按圖4.1所示輸入數(shù)據(jù),可得到如圖4.20所示的輸出。,圖4.19 程序運(yùn)行結(jié)果,圖4.20 程序運(yùn)行結(jié)果,4.4.4 傳引用方式,以傳值方式傳遞引用類型的參數(shù)時(shí),有可能更改引用所指向的數(shù)據(jù),如數(shù)組元素的值。但是無法更改引用本身的值;也就是說,在方法內(nèi)不能使用new運(yùn)算符對(duì)原始數(shù)組進(jìn)行重新分配內(nèi)存。若要這樣做,那該怎么辦呢?如果希望通過傳遞一個(gè)值類型參數(shù),在方法內(nèi)對(duì)該參數(shù)的修改能夠返回給原始參數(shù),那又該怎么辦呢?為實(shí)現(xiàn)這樣的編程,C#提供了關(guān)鍵字ref和out。 ref和out關(guān)鍵字指出一個(gè)值類型變量或引用類型變量應(yīng)該以傳引用方式傳遞。如果使用關(guān)鍵字ref和out通過引用傳遞變量,則方法能夠修改變量本身。具體說來,如果參數(shù)為對(duì)象變量,則在方法內(nèi)可以給它分配新的對(duì)象。這種重新分配也會(huì)影響到調(diào)用程序中的對(duì)象變量。如果參數(shù)為值類型變量,在方法中對(duì)參數(shù)所做的任何更改都將反映在該變量中,因此參數(shù)使用ref和out關(guān)鍵字后被調(diào)用的方法能夠修改原始變量。 若要使用 ref 參數(shù),必須將參數(shù)作為 ref 參數(shù)顯式地傳遞到方法。ref 參數(shù)的值被傳遞到 ref 參數(shù)。傳遞到 ref 參數(shù)的參數(shù)必須最先初始化。 out指定一個(gè)輸出參數(shù),被調(diào)用的方法會(huì)向其賦值。通常,當(dāng)方法收到一個(gè)未初始化的值時(shí),會(huì)發(fā)生編譯錯(cuò)誤,如在參數(shù)前添out關(guān)鍵字,可要求被調(diào)用的方法對(duì)其進(jìn)行初始化,并防止發(fā)生未初始化變量的錯(cuò)誤。若要使用out參數(shù),必須將參數(shù)作為out參數(shù)顯式傳遞到方法。out參數(shù)的值不會(huì)傳遞到out參數(shù)。不必初始化作為out參數(shù)傳遞的變量。然而,必須在方法返回之前為out參數(shù)賦值。out參數(shù)通常用于產(chǎn)生多個(gè)返回值的方法中。,4.4.5 以傳引用方式傳遞值類型參數(shù),1. ref參數(shù) 任務(wù)4.8:調(diào)用方法獲得多個(gè)值(使用ref參數(shù)) 主要知識(shí)點(diǎn):通過傳引用方式傳遞值類型變量。 問題描述:在矩形Rectangle類中,聲明方法getXYWH,用戶調(diào)用該方法時(shí),可一次獲得表示矩形位置的x、y坐標(biāo)和矩形的寬度(Width)、高度(Height)。 解決方案: (1) 創(chuàng)建一個(gè)空項(xiàng)目Testref,向該項(xiàng)目添加如下代碼文件 (2) 添加System.Windows.Forms.dll引用后。按Ctrl+F5鍵執(zhí)行該應(yīng)用程序,可得到如圖4.24所示的輸出。 2. out參數(shù) 任務(wù)4.9:調(diào)用方法獲得多個(gè)值(使用out參數(shù)) 主要知識(shí)點(diǎn):使用out參數(shù)。 問題描述:使用out參數(shù)修改上一個(gè)示例,使其完成同樣的任務(wù)。 解決方案: 使用out參數(shù)調(diào)用方法時(shí),不必對(duì)out參數(shù)初始化,由被調(diào)用的方法為其賦值。 編譯并運(yùn)行程序,可得到如圖4.25所示的輸出。 3. ref參數(shù)與out參數(shù)的比較 任務(wù)4.10:改變矩形位置 主要知識(shí)點(diǎn): ref參數(shù)與out參數(shù)的區(qū)別。 問題描述:聲明一矩形類,在矩形類中聲明一方法ChangePos,該方法將矩形的位置坐標(biāo)x、y改變?yōu)閰?shù)指定的量,并將修改后的矩形的位置坐標(biāo)x、y返回。 解決方案:由于要求方法返回兩個(gè)值,因此必須使用傳引用方式傳遞參數(shù),因?yàn)榉椒ㄒ褂脗鬟f參數(shù)的值,所以必須采用ref參數(shù)。 (1)創(chuàng)建一個(gè)空項(xiàng)目Testref1,在該項(xiàng)目中添加如下類: (2)編譯并運(yùn)行程序,可得到如圖4.26所示的輸出。,圖4.24 程序運(yùn)行結(jié)果,圖4.25 程序運(yùn)行結(jié)果,圖4.26 程序運(yùn)行結(jié)果,4.4.6 以傳引用方式傳遞引用類型參數(shù),以傳值方式傳遞引用類型的參數(shù)時(shí),有可能更改引用所指向的數(shù)據(jù),如數(shù)組元素的值。但是無法更改引用本身的值;也就是說,在方法內(nèi)不能使用new運(yùn)算符對(duì)原始數(shù)組進(jìn)行重新分配內(nèi)存。可使用C#提供的ref或out關(guān)鍵字解決這一問題。我們?cè)俅螐?qiáng)調(diào),ref或out關(guān)鍵字告訴編譯器,形參將不創(chuàng)建新的存儲(chǔ)位置,形參指向與正被傳遞的參數(shù)(實(shí)參)相同的存儲(chǔ)位置。這樣如果被調(diào)用方法修改了形參的值并且返回,調(diào)用代碼的變量(實(shí)參)的值就被修改了。 注意:修改了引用類型變量的值,該變量就引用一個(gè)新的對(duì)象,也就是給該變量創(chuàng)建了一個(gè)新的對(duì)象。 下面的示例演示了采用傳引用方式傳遞引用類型參數(shù)的使用。 任務(wù)4.11:調(diào)用方法為實(shí)參創(chuàng)建新的對(duì)象 主要知識(shí)點(diǎn):通過傳引用方式傳遞引用類型變量。 問題描述:修改任務(wù)4.1中的代碼和printArray方法,演示通過引用傳遞方式向printArray方法傳遞引用類型的參數(shù)app.rainfall。由于采用引用傳遞方式傳遞參數(shù),實(shí)參和形參存儲(chǔ)位置相同,因此在方法中對(duì)形參重新創(chuàng)建對(duì)象(形參的值被修改)后,實(shí)參也被重新分配對(duì)象,也就是在被調(diào)用方法中為實(shí)參創(chuàng)建了一個(gè)新對(duì)象。 解決方案: (1) 打開任務(wù)4.1的項(xiàng)目及其代碼文件。將MonthActualApp類的printArray方法修改 (2) 修改Main方法中調(diào)用printArray方法的參數(shù)類型 (3) 按Ctrl+F5鍵來運(yùn)行程序,還是按圖4.1所示輸入數(shù)據(jù),可得到如圖4.27所示的輸出。,圖4.27 以傳引用方式傳遞引用類型參數(shù),