講義メモ ・アレンジ演習:p.140 array03.cs」の続きから p.140 array03.cs 補足【再掲載+α】 ・023行目などで用いている「Char.IsNumber(文字列s, 位置n)」は、文字列sの先頭を0文字目とした時のn文字目が、数字かどうかを返すメソッド ・よって、位置nが0であれば、文字列の先頭文字が数字であればtrue、でなければfalseを返す ・これで事前にチェックすることで、int.Parseメソッドなどで数値化できる文字列かどうかがわかるので、異常終了を防ぐことができる ・このプログラムでは、事前に1桁であることもチェックしているので、先頭文字のチェックだけで、int.Parseメソッドで数値化できるかを判断できる アレンジ演習:p.140 array03.cs【再掲載+α】 ・if文の中で「Char.IsNumber(strClass, 0) != true」などとしているが、「!Char.IsNumber(strClass, 0)」と  シンプルにできることを確認しよう ・単項!演算子については、p.89参照 作成例 //アレンジ演習:p.140 array03.cs using System; class array03 { public static void Main() { string[,] Name = new string[2, 5] { {"田中六郎", "吉田一郎", "太田太郎", "粂井康孝", "岡田三郎"}, {"横田芳子", "池田和子", "目黒貴和子", "武田信子", "園田淳子"} }; int MyClass, No; string strClass, strNo; while (true) { Console.Write("クラスは---"); strClass = Console.ReadLine(); if (strClass.Length >= 2) { Console.WriteLine("入力は1桁のみです"); continue; } if (!Char.IsNumber(strClass, 0)) { //【変更】 Console.WriteLine("数字を入力してください"); continue; } MyClass = Int32.Parse(strClass); if (MyClass <= 0 || MyClass >= 3) { Console.WriteLine("クラスは1組か2組です"); continue; } break; } while (true) { Console.Write("出席番号は---"); strNo = Console.ReadLine(); if (strNo.Length >= 2) { Console.WriteLine("入力は1桁のみです"); continue; } if (!Char.IsNumber(strNo, 0)) { //【変更】 Console.WriteLine("数字を入力してください"); continue; } No = Int32.Parse(strNo); if (No <= 0 || No >= 6) { Console.WriteLine("出席番号は1番から5番までです"); continue; } break; } Console.WriteLine("{0}クラスの出席番号{1}番は{2}さんです", strClass, strNo, Name[MyClass - 1, No - 1]); } } アレンジ演習:p.140 array03.cs つづき ・全体に冗長で問題点もあるので、下記を改良しよう ①クラス数(2)と学生数(5)を定数にして、配列の初期化や入力チェックに用いるようにしよう ②何も入力せずにEnterを押すと異常終了するので「入力長が2以上」を「入力長が1ではない」にする ③このチェックとIsNumberによるチェックはまとめて実行できる(短絡評価(p.90)にすれば良い)  そしてエラー時は「入力は数字1桁のみです」と表示すれば良い 作成例 //アレンジ演習:p.140 array03.cs using System; class array03 { public static void Main() { const int CLASS = 2, STUDENT = 5; //【追加】クラス数、生徒数 string[,] Name = new string[CLASS, STUDENT] { //【変更】 {"田中六郎", "吉田一郎", "太田太郎", "粂井康孝", "岡田三郎"}, {"横田芳子", "池田和子", "目黒貴和子", "武田信子", "園田淳子"} }; int MyClass, No; string strClass, strNo; while (true) { Console.Write("クラスは---"); strClass = Console.ReadLine(); if (strClass.Length != 1 || !Char.IsNumber(strClass, 0)) { //【変更】 Console.WriteLine("入力は数字1桁のみです");//【変更】 continue; } MyClass = int.Parse(strClass); if (MyClass < 1 || MyClass > CLASS) { //【変更】 Console.WriteLine("クラスは1組から{0}組です", CLASS); //【変更】 continue; } break; } while (true) { Console.Write("出席番号は---"); strNo = Console.ReadLine(); if (strNo.Length != 1 || !Char.IsNumber(strNo, 0)) { //【変更】 Console.WriteLine("入力は数字1桁のみです");//【変更】 continue; } No = int.Parse(strNo); if (No < 1 || No > STUDENT) { Console.WriteLine("出席番号は1番から{0}番までです", STUDENT); //【変更】 continue; } break; } Console.WriteLine("{0}クラスの出席番号{1}番は{2}さんです", strClass, strNo, Name[MyClass - 1, No - 1]); } } p.142 3次元以上の配列 ・C#の多次元配列には次元数の上限はない ・しかし、次元数が増えると要素数が増大するのでメモリの消費量に注意が必要 ・3次元配列の宣言と生成の書式: データ型[,,] 配列名 = new データ型[要素数①,要素数②,要素数③]; ・3次元配列の初期化の例(2階建ての横3縦4の迷宮)  int[,,] map = { { {1,2,3,4}, {5,6,7,8}, {9,10,11,12} }, { {1,2,3,4}, {5,6,7,8}, {9,10,11,12} } }; ・3次元配列の全要素を扱う場合、forの3重ループにして、添字①、②、③の順に扱うと良い  書式例:  for (int i = 0; i < 要素数①; i++) {   for (int j = 0; j < 要素数②; j++) {    for (int k = 0; k < 要素数③; k++) {     配列名[i, j, k]を操作    }   }  } p.143(多次元配列の次元数と要素数) ・多次元配列の次元数は、配列名.Rank で得られる ・多次元配列の全要素数は、配列名.Length で得られる ・なお、要素数は各次元の要素数の積になるが、各次元の要素数を得る方法はない  例: 2階建ての横3縦4の迷宮を表すmap[2,3,4]の要素数は2×3×4=24 アレンジ演習:p.143 array04.cs ・次元ごとの要素数を定数で与えるようにして、繰返しの回数としても用いよう 作成例 //アレンジ演習:p.143 array04.cs using System; class array04 { public static void Main() { const int X = 2, Y = 2, Z = 3; //【追記】 int[,,] ar = new int[X, Y, Z] { { {0, 1, 2}, //順に[0,0,0][0,0,1][0,0,2] {3, 4, 5} }, //順に[0,1,0][0,1,1][0,1,2] { {6, 7, 8}, //順に[1,0,0][1,0,1][1,0,2] {9,10,11} } //順に[1,1,0][1,1,1][1,1,2] }; Console.WriteLine("配列の次元 = {0}", ar.Rank); //次元数を表示 Console.WriteLine("arの個数 = {0}", ar.Length); //要素数を表示 for (int i = 0; i < X; i++) { //1番目の添字 for (int j = 0; j < Y; j++) { //2番目の添字 for (int k = 0; k < Z; k++) { //3番目の添字 Console.Write("{0}, ", ar[i, j, k]); //順に表示 } } } Console.WriteLine(); //改行 } } p.144 ジャグ配列 ・多次元配列を配列の配列として表す仕組み ・C/C++/Javaなどの多次元配列と同様の仕組み ・要素数が異なる配列を「配列の配列」にできるので、自由度が高く、容量の無駄を削減できる ・ただし、初期化や全要素の操作において、要素数の違いの配慮が必要になる ・2次元ジャグ配列の宣言の書式: データ型[][] 配列名; ・2次元ジャグ配列の生成においては、まず、配列の配列数のみを指定した定義を行う ・2次元ジャグ配列の定義の書式: 配列名 = new データ型[配列数][]; ・それから、内側の配列を必要な配列数だけ生成して、配列名[添字]に渡すことで2次元ジャグ配列にする ・2次元ジャグ配列の内側の配列の生成の書式: 配列名[添字] = new データ型[要素数]; ・2次元ジャグ配列の内側の配列の初期化の書式: 配列名[添字] = new データ型[]{値,…}; ・例:3つのグループによるモンスター名の2次元ジャグ配列  string[][] monsters = new string[3][];  monsters[0] = new string[]{"スラリン","リムル"};  monsters[1] = new string[]{"ヴェルドラ","ヴェルザード","ヴェルグリンド"};  monsters[2] = new string[]{"カレラ"}; アレンジ演習:p.144 jagged01.cs ・各要素数を定数で与えるようにして、繰返しの回数としても用いよう 作成例 //アレンジ演習:p.144 jagged01.cs using System; class jagged01 { public static void Main() { const int X = 2, Y = 3; //【追加】ジャグ配列を構成する配列数,要素配列の要素数 int[][] ar; //ジャグ配列の宣言 ar = new int[X][]; //【変更】ジャグ配列(の外側)を生成 ar[0] = new int[Y]; //【変更】ジャグ配列[0]になる配列を生成 ar[1] = new int[Y]; //【変更】ジャグ配列[1]になる配列を生成 for (int i = 0; i < X; i++) { //【変更】ジャグ配列を構成する全配列について繰返す for (int j = 0; j < Y; j++) { //【変更】要素配列の全要素について繰返す ar[i][j] = (i + 1) * (j + 1); //(添字+1)の積によって要素値を決める } } for (int i = 0; i < X; i++) { //【変更】ジャグ配列を構成する全配列について繰返す for (int j = 0; j < Y; j++) { //【変更】要素配列の全要素について繰返す Console.WriteLine("ar[{0}][{1}] = {2}", i, j, ar[i][j]); //表示 } } } } p.146(ジャグ配列の要素数) ・2次元ジャグ配列の配列数は、2次元ジャグ配列名.Lengthで得られる ・ジャグ配列の配列[n]の要素数は、2次元ジャグ配列名[n].Lengthで得られる ・例:3つのグループによるモンスター名の2次元ジャグ配列  string[][] monsters = new string[3][];  monsters[0] = new string[]{"スラリン","リムル"};  monsters[1] = new string[]{"ヴェルドラ","ヴェルザード","ヴェルグリンド"};  monsters[2] = new string[]{"カレラ"};  Console.WriteLine(monsters.Length); //3  Console.WriteLine(monsters[0].Length); //2  Console.WriteLine(monsters[1].Length); //3  Console.WriteLine(monsters[2].Length); //1 アレンジ演習:p.146 jagged02.cs ・要素配列数を定数で与えるようにして、繰返しの回数としても用いよう ・要素配列の初期化で要素数を記述しないようにしよう ・2つのfor文を2重ループにしよう 作成例 //アレンジ演習:p.146 jagged02.cs using System; class jagged02 { public static void Main() { const int X = 2; //【追加】ジャグ配列を構成する配列数 string[][] name = new string[X][]; //【変更】 name[0] = new string[2]{"田中", "工藤"}; name[1] = new string[3]{"吉田", "佐藤", "池田"}; for (int i = 0; i < X; i++) { //【変更】 for (int j = 0; j < name[i].Length; j++) { //【変更】 Console.WriteLine(name[i][j]); //【変更】 } } } } p.147 暗黙の型指定がなされた配列 ・配列を初期化によって生成する場合、型を省略してvar型にできる ・書式: var 配列名 = new [] {値, …}; ・こうすると、配列の型は指定されたすべての値を格納できる型に決まる ・例: var s = new []{"ABC", "DE"}; //string型になる ・例: var d = new []{1, 1.2f, 3.14}; //double型になる ・指定されたすべての値を格納できる型がない場合や、null指定の場合はエラーになる ・例: var e = new []{"1", 1.2f}; //エラー ・例: var f = new []{null, null}; //エラー p.147(int型を返すmainメソッド) ・mainメソッドは通常戻り値型はvoidだが、終了状態を示す整数値を返す「int main(){…}」とすることもできる ・こうした場合、正常終了であれば「return 0;」を、でなければ「return 負の数;」を記述できる ※ p.147 var03.csの場合「return 0;」しかしていないので、int型を返すmainメソッドにする必要性はない p.147(配列とGetType) ・配列名.GetTypeは、文字列「.NET型名[]」を返す。例:"System.Int32[]" ・2次元配列名.GetTypeは、文字列「.NET型名[,]」を返す。例:"System.String[,]" ・2次元ジャグ配列名.GetTypeは、文字列「.NET型名[][]」を返す。例:"System.Double[][]" アレンジ演習: p.147 var03.cs ・2次元配列もvar型にできることを確認しよう。また、GetTypeでの表示を確認しよう。 ・ジャグ配列もvar型にできることを確認しよう。また、GetTypeでの表示を確認しよう。 作成例 //アレンジ演習:p.147 var03.cs using System; class var03 { public static void Main() { var name = new []{"太郎", "次郎", "三郎", "四郎"}; for (var i = 0; i < name.Length; i++) { Console.WriteLine(name[i]); } Console.WriteLine("nameの型は{0}", name.GetType()); //System.String[] var f = new[] { 0.5, 0.9, 1.5, 2.3 }; for (var i = 0; i < f.Length; i++) { Console.WriteLine(f[i]); } Console.WriteLine("fの型は{0}", f.GetType()); //System.Double[] //【以下追加】 var names = new [,]{{"太郎", "次郎" }, {"三郎", "四郎" } }; //2次元配列 Console.WriteLine("namesの型は{0}", names.GetType()); //System.String[,] var namej = new []{new[]{"太郎", "次郎" }, new[]{"三郎"} }; //ジャグ配列 Console.WriteLine("namejの型は{0}", namej.GetType()); //System.String[][] } } p.148 1次元配列のソート ・C#が提供するArrayクラスのSortメソッドに引数として配列名を渡すと、全要素を昇順(小⇒大)に整列してくれる ・また、このクラスのReverseメソッドに引数として配列名を渡すと、全要素を逆順にしてくれる ・よって、全要素を降順(大⇒小)に整列するには、Sortメソッド、Reverseメソッドの順に用いると良い アレンジ演習:p.148 sort01.cs ・nameをvar型にしても動作することを確認しよう ・2次元配列やジャグ配列を渡すとどうなるか確認しよう  ⇒ 文法エラーにはならないが、実行時エラーになり異常終了する 作成例 //アレンジ演習:p.148 sort01.cs using System; class sort01 { public static void Main() { var name = new []{"Eric", "Peter", "Frank", "Kate", "Thomas"}; //【変更】 for (int i = 0; i < name.Length; i++) { Console.WriteLine(name[i]); } Console.WriteLine(); Array.Sort(name); //昇順にソートする for (int i = 0; i < name.Length; i++) { Console.WriteLine(name[i]); } Console.WriteLine(); Array.Reverse(name); //逆順にする(降順にソートしたことになる) for (int i = 0; i < name.Length; i++) { Console.WriteLine(name[i]); } //【以下追加】 var names = new [,]{{200, 300 }, {100, 500 } }; //2次元配列 //Array.Sort(names); //昇順にソートする ⇒ 実行時エラー var namej = new []{new[]{"太郎", "次郎" }, new[]{"三郎"} }; //ジャグ配列 //Array.Sort(namej); //昇順にソートする ⇒ 実行時エラー } } p.150 foreach文による反復処理 ・配列などのデータ構造に対して「全要素について繰返す」専用の構文としてforeach文がある  ※ 似た構文がfor文の拡張型などとして各言語で提供されているが、文法の差があるので注意 ・データ構造から順に1要素を取り出して作業用変数に格納して扱う仕掛け ・構文: foreach (型 作業変数名 in 配列などのデータ構造名) { 処理内容 } ・作業変数はforeachブロック内においてのみ有効で、参照専用なので要素を書き換える処理には向かない ・作業変数の型は指定可能だが、varにしておくことが多い ・なお、foreachの対象になるデータ構造をコレクションともいう アレンジ演習:p.150 foreach01.cs ・配列と作業変数を全てvar型にできることを確認しよう ・foreachブロックの中で作業変数に値を代入しようとするとエラーになることを確認しよう ・2次元配列を渡すとどうなるか確認しよう  ⇒1次元配列と同様に全要素が順に用いられる ・ジャグ配列を渡すとどうなるか確認しよう  ⇒foreachを2重ループにすることで、要素配列から全要素が順に用いられる 作成例 //アレンジ演習:p.150 foreach01.cs using System; class foreach01 { public static void Main() { var Animal = new string[]{"犬", "猫", "雉", "猿"}; //string[]型になる var Num = new int[]{10, 20, 30, 40}; //int[]型になる foreach (var str in Animal) { //string型になる Console.WriteLine(str); } Console.WriteLine(); foreach (var i in Num) { //int型になる Console.WriteLine(i); //i = 0; //文法エラーになる } //【以下追加】 Console.WriteLine(); var names = new [,]{{200, 300 }, {100, 500 } }; //2次元配列 foreach (var i in names) { //int型になる Console.WriteLine(i); } //【以下追加】 Console.WriteLine(); var namej = new []{new[]{"太郎", "次郎" }, new[]{"三郎"} }; //ジャグ配列 foreach (var i in namej) { //String[]型になる //Console.WriteLine(i); //System.String[]になってしまう foreach (var j in i) { //string型になる Console.WriteLine(j); //値が表示される } } } } p.152 練習問題 ex0601.cs ヒント ① intまたはvar型の変数として、受験者数、合計点を0で初期化 ② コンソールから受験者数を入力し整数化 ※0以下が入力されたらやりなおし ③ 受験者数を要素数とする点数の配列を生成 ④ 受験者数の分、下記を繰返す  ・コンソールから点数を入力し整数化してて点数[添字]に代入  ・点数を合計点に足しこむ ⑤ 合計点を実数化してから受験者数で割って平均点を得て表示 ⑥ 点数の配列をソートし、逆順にする ⑦ 点数の配列の全要素を表示 作成例 //p.152 練習問題 ex0601.cs using System; class ex0601 { public static void Main() { var num = 0; //受験者数 var sum = 0; //合計点 do { Console.Write("受験者数:"); num = int.Parse(Console.ReadLine()); } while (num <= 0); //正の数が入力されるまで繰返す var point = new int[num]; //受験者数分の配列を生成 for (int i = 0; i < num; i++) { //受験者数分だけ繰返す Console.Write("{0}番の点数:", i + 1); point[i] = int.Parse(Console.ReadLine()); sum += point[i]; //合計に足し込む } Console.WriteLine("平均点={0}", (double)sum / num); //合計を実数化して受験者数で割る Array.Sort(point); //昇順にソート Array.Reverse(point); //逆順にすると降順になる Console.WriteLine("*** 点数(降順)***"); foreach (var i in point) { //全点数について繰返す Console.WriteLine(i); } } } 第7章 クラスの基礎 p.153 クラスとは何か ・クラスは「データと処理の設計図」であり、C#ではプログラムそのものもクラスとして記述する ・よって、ここまで作成したプログラムのすべてが「class クラス名{処理内容}」という形式になっている ・クラスは呼び出されて設計図として用いられ、動作用の実体がメモリ上に生成される ・この動作用の実体をオブジェクト(インスタンス)という ・よって、ここまで作成したプログラムも、実行指示によって動作用のオブジェクトが生成されて動作した ・プログラマは、実行用のクラスに加えて、それが利用するクラスを定義して用いることができる ・その場合、実行用のクラスの中で、利用するクラスのオブジェクトを生成して用いる p.154 簡単なクラスを定義しよう ・クラスにはデータや実行用のメソッドなどを含むことができる ・ここまで作成したプログラムにおいては、1クラスの中にMainという1つのメソッドが含まれている ・クラスに含まれるデータや実行用のメソッドなどをメンバという ・今まで定義してきた変数はすべてMainメソッドの中だったが、Mainメソッドの外に定義することで、変数をクラスのメンバ(データメンバ)にすることができる ・これをクラス変数といい、メソッドとは独立して扱うことができる ・定義書式: アクセス修飾子 データ型 変数名; ・アクセス修飾子はメンバをクラスの外部から利用可能にするかどうか等を指定するもので、publicにすると、外部から利用可能 ・Mainメソッドがpublic指定なのは、C#システムから呼び出し可能にするため ・外部から利用可能にする必要がなければ、privateとすることで、クラス内でのみ利用可能にでき、安全性が高くなる ・クラスの定義書式: class クラス名 { メンバの定義; … } ・クラスのメンバはクラス変数のみでも良いので、複数の型が異なる変数をまとめて扱う場合にも有効  ※ C言語における構造体をより強力に実装できる ・クラス変数のみのクラスの例  class Monster { //モンスタークラス(名前とHPとMPをデータメンバとして持つ)   public string name;   public int hp;   public int mp;  } p.155(クラスからのオブジェクトの生成) ・プログラム内で定義したクラスを用いるには、基本的にオブジェクトを生成する必要がある ・クラスからのオブジェクトの生成にはnew演算子を用いる ・生成したオブジェクトはクラスを型とする変数で扱い、new演算子の戻り値を代入することで利用可能になる ・この戻り値はオブジェクトへの参照(p.40)なので、クラスを型とする変数は参照型になる ・宣言書式: クラス名 参照変数; ・生成書式: 参照変数 = new クラス名(); //カッコ内の利用方法は後述 ・この宣言と生成は同時に行うことができる ・宣言と生成の書式: クラス名 参照変数 = new クラス名(); ・例: Monster rimuru = new Monster(); //Monsterクラスのオブジェクトrimuruの生成 提出:p.152 練習問題 ex0601.cs 次回予告:p.155 簡単なクラスを定義しよう(データメンバの利用)から