PPT5 - NHU IMBI Lab

Download Report

Transcript PPT5 - NHU IMBI Lab

第五部分
1
C#程式設計 – 南華大學資管系
C# 程式設計
不規則(踞齒式)陣列(Jagged Array) 1/4 P.8-30
 若第二維配置的元素個數都相同,有時會造成記
憶體的浪費。
班級一
“郭靖”
C#程式設計
 3個班級的學生人數並不相同
“黃蓉”
班級二 “楊過”
“小龍女”
班級三 “張無忌”
“趙敏”
“周伯通”
(1) 宣告與建立Jagged Array //動態配置
string[ ][ ] classes = new string[3][ ]; // classes.Length = ?
classes[0] = new string[2]; // classes[0].Length = ?
classes[1] = new string[3]; // classes[1].Length = ?
classes[2] = new string[2]; // classes[2].Length = ?
2
不規則(踞齒式)陣列(Jagged Array) 2/4
classes
0
1
●
2
C#程式設計
陣列元素可以是另一個一維陣列。
0
0
1
1 ●
0
1
●
2
(2) 給值
classes[0][0] = “郭靖”;
classes[0][1] = “黃蓉”;
classes[1][0] = “楊過”;
classes[1][1] = “小龍女”; classes[1][2] = “周伯通”;
classes[2][0] = “張無忌”; classes[2][1] = “趙敏”;
3
不規則(踞齒式)陣列(Jagged Array) 3/4
(3) 建立陣列時同時給初值
(a) string[ ][ ] classes = new string [3][ ];
C#程式設計
classes[0] = new string[ ] /*不可省略*/{“郭靖”, ”黃蓉”};
classes[1] = new string[ ] { “楊過”, ”小龍女”, ”周伯通”};
classes[2] = new string[ ] {“張無忌”, ”趙敏”};
(b) string[][] classes = new string[][] {
new string[] {“郭靖”, ”黃蓉”},
new string[] {“楊過”, ”小龍女”, ”周伯通”},
new string[] {“張無忌”, ”趙敏”}
};
4
不規則(踞齒式)陣列(Jagged Array) 4/4
(4) 使用巢狀迴圈走訪不規則陣列
(a) for (int i = 0; i < classes.Length; i++) {
C#程式設計
for (int j = 0; j < classes[i].Length; j++)
Console.Write(classes[i][j] + ” “);
Console.WriteLine();
}
(b) foreach (string[] c in classes) {
foreach (string s in c)
Console.Write(s + ” “);
Console.WriteLine();
}
5
練習:購物系統(動態配置儲存空間) 1/6
(a) 表單載入時,
C#程式設計
lblCounter.Text = “共有0個顧客”;
(b) 配置紀錄交易的實體成員
// 假設至多30筆交易
string[][] trans = new string [30][];
char[] gender = new char[30];
string[] name = new string [30];
int Counter = 0;
6
練習:購物系統(動態配置儲存空間) 2/6
(c) 輸入資料,按”輸入”鈕
if (Counter >= 30) MessageBox.Show(“儲存空間已滿”, ”錯誤”);
else { //紀錄交易的相關資訊
C#程式設計
name [ Counter ] = txtName.Text;
if (rdbMale.Checked) gender[ Counter ] = ‘男’;
else gender[ Counter ] = ‘女’;
// 檢查共買了多少商品
int ctr = 0;
if (CheckBox1.Checked) ctr++;
…
if (CheckBox5.Checked) ctr++;
// 動態配置儲存交易商品的陣列
trans[ Counter ] = new string[ ctr ];
7
練習:購物系統(動態配置儲存空間) 3/6
// 儲存購買的商品名稱
ctr = 0;
…
if (CheckBox5.Checked) trans[ Counter ][ ctr++ ] = CheckBox5.Text;
// 顯示新交易資訊
string output = “新顧客\r\n”;
output t = name[ Counter ] + ”,” + gender[ Counter ];
for (int i = 0; i < ctr; i++)
output += “,” + trans[ Counter ][ i ];
txtOutput.Text = output;
8
C#程式設計
if (CheckBox1.Checked) trans[ Counter ][ ctr++ ] = CheckBox1.Text;
練習:購物系統(動態配置儲存空間) 4/6
Counter++; // 顧客數加1
lblCounter.Text = “共有” + Counter + ”位顧客”;
C#程式設計
//清除介面上輸入的資料
txtName.Text = “ ”;
rdbMale.Checked = true;
CheckBox1.Checked = false;
…
CheckBox5.Checked = false;
txtName.Focus(); // 取得焦點
} // else 紀錄交易的相關資訊
9
練習:購物系統(動態配置儲存空間) 5/6
(d) 按”列表”鈕
string str = “顧客列表\r\n”;
str += (i+1) + ”: ”;
str += name[i] + ”, ” + gender[i];
//輸出購買的所有商品
C#程式設計
for (int i = 0; i < Counter; i++) {
//建立第i位顧客的交易資訊
for(int j = 0; j < trans[i].Length; j++)
str += “, ” + trans[i][j];
str += “\r\n”;
}
txtOutput.Text = str;
txtName.Focus();
10
練習:購物系統(動態配置儲存空間) 6/6
(e) 按”搜尋”鈕
C#程式設計
string n = txtName.Text;
int i = 0;
for (i = 0; i < Counter; i++)
if( name[ i ] == n) break;
if( i < Counter ) { //找到
string str = “!!! 搜尋結果 !!!\r\n”;
str += name[ i ] + ”, ” + gender[ i ];
for (int j = 0; j < trans[i].Length; j++) str += “, ” + trans[ i ][ j ];
txtOutput.Text = str;
} else
txtOutput.Text = “!!! 搜尋結果 !!!\r\n沒有找到” + n;
txtName.Text = “”;
txtName.Focus( );
11
函數(方法)與參數傳遞 (p.7-3)
 完成特定功能的程式片段,會在不同的地方重覆
使用到
下”產生數字”鈕時,隨機產生新的數字
C#程式設計
例如:(a) 在猜數字遊戲中,在”表單載入”或按
(b) 輸入5個成績,計算幾人及格,各等級
有多少人
 造成程式碼冗長,而且不易維護
 將完成特定功能的程式片段組織成函式(方法)。寫
一次可重複(呼叫)使用。
12
函數(方法)呼叫示意圖 (1)
‧表單載入
Form1_Load() {
‧按”產生數字”鈕
Button1_Click() {
// 隨機產生新數字 ,更新界面
//隨機產生新數字,更新界面
…
}
}
Form1_Load() {
Button1_Click() {
gen_Rnd_Num() ;
}
C#程式設計
…
gen_Rnd_Num() ;
}
void gen_Rnd_Num() {
…
}
13
函數(方法)呼叫示意圖 (2)
成績轉換(成績一);
.
.
.
等級轉換(成績二);
.
.
.
等級轉換(成績五);
-方法的呼叫包含三個機制:
(a) 參數傳遞
(b) 控制權移轉
(c) 回傳值
C#程式設計
取得成績一
將成績轉換成等級
.
.
.
轉換成績二為等級
.
.
.
轉換成績五為等級
成績
轉換
等級
Interface
(使用界面)
14
模組化程式設計: 工作分解示意圖
資料處理
取得資料
資料分析
void DataProcessing()
{
// 宣告變
數
…
getData(~);
analyzeData(~);
outputData(~);
}
分析二
void getData(~){
…
}
void
analyzeData(~){
analysis1(~);
analysis2(~);
}
void
outputData(~){
…
void
analysis1(~){
…
}
void
analysis2(~){
…
C#程式設計
分析一
輸出結果
DataProcessing() {
// 宣告變數
…
// 取得資料
…
// 分析一
…
// 分析二
…
// 輸出結果
…
}
15
建立C#函數 (程序、副程式) (P.7-4)
 C#函數是一個可以重覆執行的程式區塊。在C#
中屬於類別的成員,稱為方法(methods)。
C#程式設計
 事件處理程序、類別或物件的成員方法。
 自訂功能的函數:將程式區塊使用一個函數名
稱來代替,以便呼叫函數來執行特定功能。
16
方法的宣告 (P.7-4)
[存取修飾詞] 傳回值型態 方法名稱(參數1,參數2….)
{
C#程式設計
程式碼
return 值|運算式;
}
bool isPass (int s) {
if (s >= 60) return true;
else return false;
}
void showTitle() {
lblOutput.Text = “C#程式設計\n”;
}
char ScoreToGrade (int s) {
if (s >= 90) return ‘A’;
else if(s >= 80) return ‘B’;
else if(s >= 70) return ‘C’;
else if(s >= 60) return ‘D’;
else return ‘E’;
}
17
練習:輸入五個成績,分別顯示各
成績是否及格,等級是什麼? 1/2
(1) string res = “”;
if( S1 >= 60 ) res += S1 + ”:及格, ”;
else res += S1 + ”:不及格, ”;
C#程式設計
int S1 = Convert.ToInt32( txtNum1.Text );
if( S1 >= 90 ) res += “等級為A\r\n”;
else if ( S1 >= 80 ) res += “等級為B\r\n”;
…
else res += “等級為E\r\n”;
… //S2, S3, S4, S5相同作法
18
練習:輸入五個成績,分別顯示各
成績是否及格,等級是什麼? 2/2
(2) 使用函數呼叫
int S1 = Convert.ToInt32( txtNum1.Text );
C#程式設計
string res = “”;
if( isPass( S1 ) ) res += S1+”:及格, ”;
else res += S1+”:不及格, ”;
res += “等級為” + ScoreToGrade( S1 ) + ”\r\n”;
…
//S2, S3, S4, S5相同作法
19
練習:利用陣列儲存5個成績,改寫程式
int[] s = new int[5];
s[0] = Convert.ToInt32( txtNum1.Text );
…
string res = “”;
C#程式設計
s[4] = Convert.ToInt32( txtNum5.Text );
for (int i = 0; i < 5; i++) {
if ( ispass( s[ i ] ) ) res += s[ i ] + ”:及格, ”;
else res += s[ i ] + ”:不及格, ”;
res += “等級為” + ScoreToGrade( s[ i ] ) + ”\r\n”;
}
txtOutput.Text = res;
20
練習:統計及格幾人,各等級幾人(一) 1/2
(a) int pass = 0;
int A = 0, B = 0, C = 0, D = 0, E = 0; //使用五個變數來記錄
for( int i = 0; i < 5; i++) {
else res += s[ i ] + ”不及格, ”;
char g = ScoreToGrade( s[ i ] );
C#程式設計
if( ispass( s[ i ] ) ) { res += s[ i ] + ”:及格, ”; pass++; }
res += “等級為”+ g + ”\r\n”;
switch( g ) {
case ‘A’: A++; break;
case ‘B’: B++; break;
…
case ‘E’: E++; break;
}
}
21
練習:統計及格幾人,各等級幾人
(一) 2/2
// 輸出統計資訊
res += “等級A” + A + ”人\r\n”;
C#程式設計
res += “及格:” + pass + ”人\r\n”;
…
res += “等級E” + E + ”人\r\n”;
txtOutput.Text = res;
22
練習:統計及格幾人,各等級幾人(二) 1/2
(b) int pass = 0;
int[] ctr = {0, 0, 0, 0, 0}; //使用陣列來記錄
0
1
2
3
4
0
0
0
0
0
‘A’-’A’
‘B’-’A’
C#程式設計
ctr
‘C’-’A’ ‘D’-’A’ ‘E’-’A’
23
練習:統計及格幾人,各等級幾人(二) 2/2
for (int i = 0; i < 5; i++) {
if ( ispass( s[ i ] ) ){ res += s[ i ] + ”:及格, ”;
pass++; }
else res += s[ i ] + ”:不及格, ”;
res += “等級為” + g + ”\r\n”;
ctr[ g - ’A’ ]++;
C#程式設計
char g = ScoreToGrade( s [ i ] );
}
//輸出統計資訊
res += “及格:” + pass + ”人\r\n”;
for (int i = 0; i < 5; i++)
res += “等級”+ (char)(‘A’ + i) + ”:” + ctr[ i ] + ”人\r\n”;
txtOutput.Text = res;
24
參數的傳遞方式 - 傳值呼叫 (p.7-15)
 將變數值(複製一份)傳入函數,在函數內無法變更此變數的值
 C#預設使用傳值呼叫(Call by value)
 傳遞陣列(傳值,此值是陣列的reference)
int sum = 0;
for (int i = 0; i < a.Length; i++)
sum += a[ i ];
return sum;
C#程式設計
int SumArray( int[] a ) {
}
 練習:輸出五個成績的和與平均
int sum = SumArray( s );
res += “和 = ” + sum + ”\r\n”;
res += “平均 = ” + (sum / 5.0) + ”\r\n”;
25
參數傳遞 - 傳址呼叫(call by reference) (p.7-15)
 將變數的位址傳入函數,在函數內可透過該位址”存” 、”取”
該變數的值
 交換兩變數的值
(b) call by ref (√)
void swap(ref int a, ref int b) {
int t = a;
a = b;
b = t;
}
……
int a = 10, b = 5;
swap(ref a, ref b);
……
C#程式設計
(a) call by value (X)
void swap(int a, int b){
int t = a;
a = b;
b = t;
}
……
int a = 10, b = 5;
swap(a, b);
……
26
參數傳遞 - 傳出呼叫 (call by Output)
 用來接收函數傳出來的值。其傳入的變數不需要指定初值
 計算陣列的最大和最小值
C#程式設計
void MaxMinArray(int [] a, out int max, out int min) {
max = a[0]; min = a[0];
for (int i = 1; i < a.Length; i++) {
if( a[ i ] > max ) max = a[ i ];
if( a[ i ] < min ) min = a[ i ];
}
}
 輸出5個成績的最高分和最低分
int max, min;
MaxMinArray(s, out max, out min);
res += “最高分 = ” + max + ”\r\n”;
res += “最低分 = ” + min + ”\r\n”;
27
方法多載(Overloading Methods) 1/2 (p.16-18)
C#的類別允許擁有兩個以上的同名方法,只需傳遞
的參數個數或資料型態不同即可,稱為Overloads。
C#程式設計
 建立Overloading Methods就是建立多個同名但仍可透過參
數而區別的方法。
 int[] intArray = {1, 2, 3, 4, 5};
int sum = sumArray( intArray ); //OK
label1.Text = sum.ToString();
28
方法多載(Overloading Methods) 2/2 (p.16-18)
 double[] dArray = {10.0, 20.0, 30.0, 40.0, 50.0};
 定義能處理double Array和的方法
double sumArray( double[] a ) {
double sum = 0.0;
for (int i = 0; i < a.Length; i++)
sum += a[ i ];
return sum;
}
→ OK, 依參數型態的不同,呼叫對應的方法
C#程式設計
double dSum = sumArray( dArray );
→ Error: 無法從double[] 轉換為int[]
29
檔案的處理 (p.13-2)
 匯入System.IO名稱空間,就可以使用相關的I/O類別來存
取檔案系統,或是處理文字或二進位檔案的「串流」
(Streams)。
C#程式設計
 利用OpenFileDialog控制項和SaveFileDialog控制項來選擇
「開啟」和「儲存」的檔案。(p.13-38)
 利用FileInfo, StreamReader和StreamWriter類別來處理文字
檔資料的讀取和寫入(儲存)。 (p.13-21)
資料
來源
讀取資料
寫入資料
程式
輸入串流
輸出串流
資料
輸出
30
成績處理-資料的輸入、儲存和匯入
成績資料的輸入
名字用一維陣列來儲存
C#程式設計
成績用二維陣列來儲存
 配置儲存資料的記憶體
const int MAX_CAPACITY = 30; (p. 3-12)
string[] name = new string[ MAX_CAPACITY ];
int [,] scores = new int[ 2, MAX_CAPACITY ];
int counter = 0;
31
按下”輸入資料”鈕 (新增一筆)
(1) 測試陣列的容量,有空間則儲存,否則提示訊息
if ( counter < MAX_CAPACITY ) {
name[ counter ] = txtName.Text;
scores[ 0, counter ] = Convert.ToInt32( txtChinese.Text );
counter++;
C#程式設計
scores[ 1, counter ] = Convert.ToInt32( txtMath.Text );
ShowData(); //在界面上顯示資料
}
else MessageBox.Show(“容量已滿”, ”錯誤”, …, …);
(2) 在界面上顯示資料( ShowData()函式 )
lblCounter.Text = “共有” + counter + ”人”;
string res = “名字\t國文\t數學\r\n”;
for( int i = 0; i < counter; i++)
res += (name[ i ] + ”\t” + scores[ 0, i ] + ”\t” + Scores[ 1, i ] + ”\r\n”);
txtOutput.Text = res;
32
將資料存檔 1/2
(a) 新增”儲存資料”鈕
(b) 按下”儲存資料”鈕

利用SaveFileDialog控制項的ShowDialog方法來選擇檔案 (p. 13-39)
‧name設為sfdSave
C#程式設計
‧將Filter屬性設為”資料檔案(*.txt) | *.txt | 所有檔案(*.*) | *.*”
‧RestoreDirectory設為true
‧利用FileName屬性取得選取的檔案完整路徑
‧若在Dialog中選擇的檔案已存在,則會顯示”該檔案已存在,
是否要取代它?”
‧若輸入test,則FileName為……\test.txt,但尚未產生該檔案。
33
將資料存檔 2/2
 加入Using System.IO;
利用FileInfo物件的CreateText()建立(或取代)檔案,並得到StreamWriter物件
(p.13-14, P.13-21)
if ( sfdSave.ShowDialog() == DialogResult.OK ) {
FileInfo finfo = new FileInfo( sfdSave.FileName );
StreamWriter sw = finfo.CreateText();
for( int i = 0; i < counter; i++ ) {
sw.WritLine( name[ i ] );
sw.WritLine( scores[ 0, i ] );
sw.WritLine( scores[ 1, i ] );
}
sw.Flush();
sw.Close();
}
C#程式設計
 利用多載的WriterLine(~)方法儲存資料 (p.13-22) (檔案資料的儲存格式)
 關閉檔案串流 (p.13-23)
 程式碼
34
新增”載入資料”鈕 1/2
 利用OpenFileDialog控制項來選擇檔案,設定Filter,
RestoreDirectory屬性 (p.13-40)
 利用ReadLine()方法讀入資料 (p.13-22)
C#程式設計
 利用FileInfo物件的OpenText()開啟檔案,並得到
StreamReader物件 (p.13-21)
 回傳值是string 物件
 利用Convert.ToInt32(~)轉換成int
 利用Peek()方法,判斷是否end of file (-1)
 關閉串流
 更新界面的輸出 ( 利用ShowData() )
35
新增”載入資料”鈕 2/2
 程式碼
C#程式設計
if( ofdOpen.ShowDialog() == DialogResult.OK ) {
FileInfo finfo = new FileInfo( ofdOpen.FileName );
StreamReader sr = finfo.OpenText();
int i = 0;
while ( sr.Peek() >= 0 ) {
name[ i ] = sr.ReadLine();
scores[ 0, i ] = Convert.ToInt32( sr.ReadLine() );
scores[ 1, i ] = Convert.ToInt32( sr.ReadLine() );
i++;
}
sr.Close();
counter = i;
ShowData();
}
36
二進位檔案的處理
資料
來源
Binary
Reader
PeekChar()
ReadString()
ReadInt32()
Close()
程式
Write(Type)
File
Flush()
Stream
Close()
Binary
Writer
C#程式設計
File
Stream
資料
輸出
 使用Filestream串流物件(二進位串流)來開啟底層的二進位檔案。開啟
的模式由FileMode常數來決定 (p.13-34)
 使用BinaryReader物件從二進位串流讀入基本型態的資料 (p.13-35)
 使用BinaryWriter物件將基本型態的資料寫入二進位串流 (p.13-34)
 在FileDialog控制項的Filter屬性中增加”二元檔案(*.dat) | *.dat”
37
新增”儲存資料(二進位檔案)”鈕
if ( sfdSave.ShowDialog() == DialogResult.OK ) {
FileStream fs = new FileStream( sfdSave.FileName, FileMode.Create);
BinaryWriter bw = new BinaryWriter( fs );
for ( int i = 0; i < counter; i++ ) {
bw.Write( name[ i ] );
C#程式設計
// 寫出資料
bw.Write( scores[ 0, i ] );
bw.Write( scores[ 1, i ] );
}
//關閉檔案
bw.Flush();
bw.Close();
fs.Close();
}
38
新增”載入資料(二進位檔案)”鈕
if ( ofdOpen.ShowDialog() == DialogResult.OK ) {
FileStream fs = new File Stream( ofdOpen.FileName, FileMode.Open );
BinaryReader br = new BinaryReader( fs );
int i = 0;
name[ i ] = br.ReadString();
C#程式設計
while( br.PeekChar() >= 0 ) {
scores[ 0, i ] = br.ReadInt32();
scores[ 1, i ] = br.ReadInt32();
i++;
}
br.Close();
fs.Close();
counter = i;
ShowData();
}
39