今週の話題

販売本数ランキング 今回トップは「桃太郎電鉄ワールド ~地球は希望でまわってる!~(Switch)」GO!
『アスタタ』不発のgumi、SBIが株を追加取得しても距離を取るのはなぜか?【ゲーム企業の決算を読む】GO!
「龍が如くスタジオ」のコアメンバーとなる人材を広く募集―セガ、中途採用オンラインカジュアル面談会を1月25日・26日・27日に開催 GO!
任天堂が時価総額10兆円を超える…DS・Wiiが絶好調だった2007年以来の高値、スイッチ新型に期待高まる GO!
カヤック、2023年世界市場アプリDL数で日本企業1位獲得を報告―新規ハイカジタイトル13本リリース GO!
新作ゲームのUIが複雑すぎる!?『スーサイド・スクワッド』皮切りにユーザー間でスマートなUIと煩雑なUIの議論勃発 GO!
Live2Dデザイナー向けに充実の研修を用意! f4samuraiが明かす採用ポイントと研修カリキュラム【alive 2023セッションレポート】GO!

SteamがAI利用タイトル容認に舵を切る―違法なコンテンツなど問題には適切なチェックで対処狙う GO!
Twitchがスタッフの約35%を解雇予定、昨年のレイオフを合わせると900人程の削減に―海外メディア報道 GO!

講義メモ:第7章 クラスの基礎

p.153 クラスと何か

・C#などのオブジェクト指向言語では、プログラムをクラスを単位として作成し、データ構造もクラスを基本として扱うことができる
※ C++のように、プログラムの一部をクラスを単位として作成するものもある
・プログラムはビルドして実行を指示することにより、記述内容に従った実体がメモリ上に生成されて動作する
・つまり、プログラム=クラスは設計図にあたり、動作する実体をオブジェクトという
・この考え方を、クラスの中で用いるデータ構造や部品に当てはめることもできる
・つまり、プログラムにおいて、他のクラスの実体を生成して用いることが、プログラムの部品化にあたる
・なお、クラスから生成したオブジェクトをインスタンスともいう

p.154 簡単なクラスを定義しよう

・最も簡単なクラスは変数のみを持つクラスで、複数の変数を持つクラスにより、C/C++でいう構造体に類似するデータ構造を表現できる
・書式: class クラス名 { アクセス修飾子 型 変数名; … }
・アクセス修飾子は主にpublicとprivateで、外部から直接アクセスを許す場合はpublicと明示する。
 内部用の場合は無指定にするか、privateと明示する
・例: class Monster { public string name; public int hp; public int mp; } //名前とHP,MPを持つ怪物
・クラスを型として変数を宣言することで、クラスから生成したインスタンスを扱うことができる
・生成には配列と同様にnew演算子を用いる
・宣言の書式: クラス名 インスタンス名;
・生成の書式: インスタンス名 = new クラス名();
・宣言と生成は同時に行うことが可能。書式: クラス名 インスタンス名 = new クラス名();
 例: Monster veldra = new Monster(); //怪物クラスから実体としてveldraを生成
・複数のインスタンスをまとめて生成できる
 例: Monster veldra = new Monster(), rimuru = new Monster(); //怪物クラスから実体としてveldraとrimuruを生成
・クラスで定義した変数は、インスタンスごとに用意されるので、インスタンス名.変数名 でアクセスできる
・クラスの中で定義したものをメンバといい、インスタンスの中の変数をインスタンス変数という
 例: veldra.name = "ヴェルドラ"; veldra.hp = 100; rimuru.mp = 500;
※「.」はドット演算子ともいい、日本語の「の」に近い
・この仕組を用いるだけでも、変数のグループ化やデータの扱いの可視化が容易になる

p.156 simpleclass.cs

//p.156 simpleclass.cs
using System;
class myclass //クラスを定義(インスタンス変数を1個もつ部品的なクラス)
{
    public int x; //外部からアクセス可能なインスタンス変数
}
class simpleclass //実行用のMainメソッドを持つクラス
{
    public static void Main()
    {
        myclass mc = new myclass(); //部品的なクラスのインスタンスを生成
        mc.x = 10; //インスタンス名.メンバ名でインスタンス変数に数値を代入
        Console.WriteLine("mc.x = {0}", mc.x); //インスタンス名.メンバ名でインスタンス変数の値を表示
    }
}

アレンジ演習:p.156 simpleclass.cs

・上記の例から以下を試そう:
  class Monster { public string name; public int hp; public int mp; } //名前とHP,MPを持つ怪物
  Monster veldra = new Monster(); //怪物クラスから実体としてveldraを生成
  veldra.name = "ヴェルドラ"; veldra.hp = 100;
・適当な表示処理を追加すること

作成例

//アレンジ演習:p.156 simpleclass.cs
using System;
class Monster //クラスを定義(インスタンス変数を3個もつ部品的なクラス)
{
    public string name; //外部からアクセス可能なインスタンス変数
    public int hp; //外部からアクセス可能なインスタンス変数
    public int mp; //外部からアクセス可能なインスタンス変数
}
class simpleclass //実行用のMainメソッドを持つクラス
{
    public static void Main()
    {
        Monster veldra = new Monster(); //部品的なクラスのインスタンスを生成
        veldra.name = "ヴェルドラ"; //インスタンス名.メンバ名でインスタンス変数に値(文字列)を代入
        veldra.hp = 100; //インスタンス名.メンバ名でインスタンス変数に数値を代入
        //インスタンス名.メンバ名でインスタンス変数の値を表示(mpは初期値の0)
        Console.WriteLine("name = {0} hp = {1} mp = {2}", veldra.name, veldra.hp, veldra.mp);
    }
}

p.157(複数のインスタンスを生成)

・メンバであるインスタンス変数は、インスタンスごとに存在する。よって、異なる変数として扱える
 例: 
 Monster veldra = new Monster(), rimuru = new Monster(); //怪物クラスから実体としてveldraとrimuruを生成
 veldra.name = "ヴェルドラ"; veldra.hp = 100; veldra.mp = 500;
 rimuru.name = "魔王リムル"; rimuru.hp = 900; rimuru.mp = 800;

p.157 simpleclass02.cs

//p.157 simpleclass02.cs
using System;
class MyClass //クラスを定義(インスタンス変数を1個もつ部品的なクラス)
{
    public int x; //外部からアクセス可能なインスタンス変数
}
class simpleclass02
{
    public static void Main()
    {
        MyClass a, b; //部品的なクラスを型とするオブジェクト名を2つ宣言
        a = new MyClass(); //部品的なクラスのインスタンスを生成してオブジェクト名aで扱う
        b = new MyClass(); //部品的なクラスの別のインスタンスを生成してオブジェクト名bで扱う
        a.x =  10; //aに含まれるインスタンス変数xに代入
        b.x = 100; //bに含まれるインスタンス変数xに代入(↑とは別のもの)
        Console.WriteLine("a.x = {0}, b.x = {1}", a.x, b.x); //別のものなので10,100となる
    }
}

アレンジ演習:p.157 simpleclass02.cs

・上記の例から以下を試そう:
  class Monster { public string name; public int hp; public int mp; } //名前とHP,MPを持つ怪物
 Monster veldra = new Monster(), rimuru = new Monster(); //怪物クラスから実体としてveldraとrimuruを生成
 veldra.name = "ヴェルドラ"; veldra.hp = 100; veldra.mp = 500;
 rimuru.name = "魔王リムル"; rimuru.hp = 900; rimuru.mp = 800;
・適当な表示処理を追加すること

作成例

//アレンジ演習:p.157 simpleclass02.cs
using System;
class Monster //クラスを定義(インスタンス変数を3個もつ部品的なクラス)
{
    public string name; //外部からアクセス可能なインスタンス変数
    public int hp; //外部からアクセス可能なインスタンス変数
    public int mp; //外部からアクセス可能なインスタンス変数
}
class simpleclass //実行用のMainメソッドを持つクラス
{
    public static void Main()
    {
        Monster veldra = new Monster(), rimuru = new Monster(); //部品的なクラスのインスタンスを2つ生成
        //インスタンス名.メンバ名でインスタンス変数に値(文字列、整数)を代入
        veldra.name = "ヴェルドラ"; veldra.hp = 100; veldra.mp = 500;
        rimuru.name = "魔王リムル"; rimuru.hp = 900; rimuru.mp = 800;
        //インスタンス名.メンバ名でインスタンス変数の値を表示
        Console.WriteLine("name = {0} hp = {1} mp = {2}", veldra.name, veldra.hp, veldra.mp);
        Console.WriteLine("name = {0} hp = {1} mp = {2}", rimuru.name, rimuru.hp, rimuru.mp);
    }
}

p.158(クラス型の変数の特性)

・クラスを型とする変数は参照型(p.40)となり、変数が持つのは参照(実体の位置情報)となる
・よって、初期化や生成により、変数にインスタンスの参照が与えられる
・そして、クラスを型とする変数どうしの代入を行うと、参照がコピーされる
・この結果、2つの変数が同じインスタンスを参照するようになる
(2つ目の変数が別名と同じ働きをするようになる)
例:
  Monster rimuru = new Monster(); //インスタンスの生成
  Monster maou = rimuru; //インスタンスの参照をコピー(maouがrimuruの別名になる)
  rimuru.hp = 10;
  Console.WriteLine(maou.hp); //10が表示される

p.158 simpleclass03.cs

//p.158 simpleclass03.cs
using System;
class MyClass //クラスを定義(インスタンス変数を1個もつ部品的なクラス)
{
    public int x; //外部からアクセス可能なインスタンス変数
}
class simpleclass03
{
    public static void Main()
    {
        MyClass a, b; //部品的なクラスを型とするオブジェクト名を2つ宣言
        a = new MyClass(); //部品的なクラスのインスタンスを生成してオブジェクト名aで扱う
        a.x = 10; //aに含まれるインスタンス変数xに代入
        b = a; //aが持つ参照をbにコピー(bはaと同じインスタンスを指すようになる)
        Console.WriteLine("b.x = {0}", b.x); //よってb経由でxの値が得られる
        b.x = 100; //b経由でxの値を変更でkる
        Console.WriteLine("a.x = {0}", a.x); //よってa経由でxの値を見ると変更されている
    }
}

提出:アレンジ演習:p.157 simpleclass02.cs

講義メモ

・p.147「暗黙の型指定がなされた配列」から

提出:アレンジ演習:p.146 jagged02.cs

・2つあるforを2重ループにして見やすくしよう
・ヒント:下記の●を0から1まで繰返せばよい
        for (int j = 0; j < name[●].Length; j++) { //含まれる配列の要素数について繰返す
            Console.WriteLine(name[●][j]); //含まれる配列の要素を表示
        }

作成例

//アレンジ演習:p.146 jagged02.cs
using System;
class jagged02 {
    public static void Main() {
        string[][] name = new string[2][]; //(2次元)ジャグ配列の宣言と上位次元の要素数=含む配列の数は2と指定
        name[0] = new string[2]{"田中", "工藤"}; //含まれる配列①の初期化(2要素)
        name[1] = new string[3]{"吉田", "佐藤", "池田"}; //含まれる配列②の初期化(3要素)
        for (int i = 0; i < name.Length; i++) { //含まれる配列数(2)について繰返す
            for (int j = 0; j < name[i].Length; j++) { //含まれる配列のそれぞれの要素数(2,3)について繰返す
                Console.WriteLine(name[i][j]); //含まれる配列の要素を表示
            }
        }
    }
}

p.147 暗黙の型指定がなされた配列

・varキーワードにより、初期化された変数の型を自動決定できる(p.61)
・これは、配列に対しても適用可能
・「var []」や「var [][]」などになるわけではなく、配列としての型になる
・書式例: var 配列名 = new []{値,…};

p.147 var03.cs

//p.147 var03.cs
using System;
class var03
{
    public static int Main()
    {
        var name = new []{"太郎", "次郎", "三郎", "四郎"}; //nameはstring[]型となる
        for (var i = 0; i < name.Length; i++) { //Lengthは4になる
            Console.WriteLine(name[i]);
        }
        var f = new[] { 0.5, 0.9, 1.5, 2.3 }; //fはdouble型になる
        for (var i = 0; i < f.Length; i++) { //Lengthは4になる
            Console.WriteLine(f[i]);
        }
        Console.WriteLine("nameの型は{0}, naの型は{1}", name.GetType(), f.GetType()); //System.String[],System.Double[]
        return 0;
    }
}

アレンジ演習:p.146 jagged02.cs ②

・配列nameをvarで暗黙の型指定ができるかどうか確認しよう
・可能であり、string[][]型になる。

作成例

//アレンジ演習:p.146 jagged02.cs
using System;
class jagged02 {
    public static void Main() {
        var name = new string[2][]; //(2次元)ジャグ配列の宣言と上位次元の要素数=含む配列の数は2と指定
        name[0] = new string[2]{"田中", "工藤"}; //含まれる配列①の初期化(2要素)
        name[1] = new string[3]{"吉田", "佐藤", "池田"}; //含まれる配列②の初期化(3要素)
        for (int i = 0; i < name.Length; i++) { //含まれる配列数(2)について繰返す
            for (int j = 0; j < name[i].Length; j++) { //含まれる配列のそれぞれの要素数(2,3)について繰返す
                Console.WriteLine(name[i][j]); //含まれる配列の要素を表示
            }
        }
    }
}

p.148 1次元配列のソート

・C#が提供するArrayというクラスがあり、配列を扱う便利なメソッド等を持っている
・その1つがArray.Sortで、引数として1次元配列名を指定すると、要素を昇順に整列する
・また、全要素を逆順にするArray.Reverseもあり、Array.Sortの後に実行することで降順の整列にできる

p.148 sort01.cs アレンジ演習

・かなや漢字での動作を確認しよう
① new string[5]{"あ", "ぁ", "ア", "ァ", "亜"};
 ⇒ ァ、ぁ、ア、あ、亜 となる
② new string[5]{"一", "二", "三", "四", "五"};
 ⇒ 一、五、三、四、二 となる
③ new double[5]{3.14, -3.14, 0.0, -1 / 0.0, 1 / 0.0}; //「-1 / 0.0」は-∞、「1 / 0.0」は∞
 ⇒ -∞、-3.14、0、3.14、∞ となる

作成例③

//アレンジ演習:p.148 sort01.cs
using System;
class sort01
{
    public static void Main()
    {
        //string[] name = new string[5]{"あ", "ぁ", "ア", "ァ", "亜"}; //①
        //string[] name = new string[5]{"一", "二", "三", "四", "五"}; //②
        double[] name = new double[5]{3.14, -3.14, 0.0, -1 / 0.0, 1 / 0.0}; //③「-1 / 0.0」は-∞、「1 / 0.0」は∞
        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]); //整列後を表示 -∞、-3.14、0、3.14、∞ となる
        }
        Console.WriteLine(); //改行
        Array.Reverse(name); //逆順にする(Sort後なので降順になる)
        for (int i = 0; i < name.Length; i++) { //全要素について
            Console.WriteLine(name[i]);
        }
    }
}

p.150 foreach文による反復処理

・for文の変型で「データ構造(コレクション)に属する全データについて繰返す」のが、foreach文
・配列を指定すると「配列の全要素について繰返す」となるので便利
・foreachでは、作業用の変数を指定して、そこに1つずつデータ(要素値)が得られる
・書式: foreach(型 作業用の変数 in 配列等のコレクション名) { 作業用の変数を用いる処理 }
※ 作業用の変数の型は、配列等のコレクションの型にするが、varにすることが多い
※ 作業用の変数は要素値のコピーなので、値を書き換えても元の値には影響しない

p.150 foreach01.cs

//p.150 foreach01.cs
using System;
class foreach01
{
    public static void Main()
    {
        string[] Animal = new string[]{"犬", "猫", "雉", "猿"};
        int[] Num = new int[]{10, 20, 30, 40};
        foreach (string str in Animal) { //配列Animalの全要素について繰返す
            Console.WriteLine(str);
        }
        Console.WriteLine(); //改行
        foreach (int i in Num) { //配列Numの全要素について繰返す
            Console.WriteLine(i);
        }
    }
}

アレンジ演習 p.148 sort01.cs ②

・foreachを用いて簡略化しよう
・作業変数の型はvarにすること

作成例

//アレンジ演習:p.148 sort01.cs ②
using System;
class sort01
{
    public static void Main()
    {
        //string[] name = new string[5]{ァ、ぁ、ア、あ、亜};
        //string[] name = new string[5]{"一", "二", "三", "四", "五"};
        double[] name = new double[5]{3.14, -3.14, 0.0, -1 / 0.0, 1 / 0.0}; //「-1 / 0.0」は-∞、「1 / 0.0」は∞
        foreach (var w in name) { //【変更】全要素について
            Console.WriteLine(w); //整列前を表示
        }
        Console.WriteLine(); //改行
        Array.Sort(name); //昇順に整列
        foreach (var w in name) { //【変更】全要素について
            Console.WriteLine(w); //整列前を表示
        }
        Console.WriteLine(); //改行
        Array.Reverse(name); //逆順にする(Sort後なので降順になる)
        foreach (var w in name) { //【変更】全要素について
            Console.WriteLine(w); //整列前を表示
        }
    }
}

p.152 練習問題 ヒント

・p.136 Average02.csを元にすると良い
・実行イメージから考えよう

受験者数:3
1人目の点数:50
2人目の点数:60
3人目の点数:80
平均点は63.3
降順にすると
80
60
50

作成例

//p.152 練習問題
using System;
class average02 {
    public static void Main() {
        Console.Write("受験者数:"); int no = int.Parse(Console.ReadLine());
        int[] point = new int[no]; //int型の配列pointを受験者数の分生成
        int sum = 0; //合計
        for (int i = 0; i < no; i++) { //全要素について繰返す(※要素値を書き換えるのでforeachは不可)
            Console.Write("{0}番:", i + 1); point[i] = int.Parse(Console.ReadLine());
            sum += point[i]; //要素値をsumに足し込む
        }
        double average = (double)sum / no; //合計を件数で割って平均値を得る
        Console.WriteLine("平均点 = {0:##.#}", average); //平均値(小数点以下1桁)を表示
        Array.Sort(point); //昇順に整列
        Array.Reverse(point); //逆順にする(Sort後なので降順になる)
        Console.WriteLine("降順にすると");
        foreach (var w in point) { //全要素について繰返す
            Console.WriteLine(w);
        }
    }
}

今週の話題

販売本数ランキング 今回トップも「スーパーマリオブラザーズ ワンダー(Switch)」GO!
にじさんじライバーの要望に応える徹底的なこだわり―エンジニアとデザイナーが語るANYCOLORの強み【alive 2023】GO!
固定費削減で黒字転換したマイネット―ファンタジースポーツへの固執は吉と出るか【ゲーム企業の決算を読む】GO!
ユーザー制作マップの“ゴーストタウン化”防ぐ―GameWith、『フォートナイト』内でのクリエイティブマップ制作・プロモーションを支援 GO!
アカツキ、ソニーグループ/コーエーテクモホールディングスとの資本業務提携および第三者割当による自己株式処分実施を決議 GO!

過去に『GTA6』の映像を流出させた青年ハッカーに「無期限入院」命令が下る―高い技能や「サイバー犯罪に復帰しようとする意思」から判断 GO!
ブロックチェーンは「実際の通貨を使用したギャンブル」?北米レーティングESRBにてNFT対応ゲームが「成人指定」対象に―Epic Games storeはポリシー変更で対象タイトル販売を継続 GO!
「にじさんじ」ANYCOLOR、“配信荒らし”との間で示談成立…無関係のコメントを執拗に連続投稿 GO!
インディーゲームで契約トラブルを避けるための3つのポイントをPLAYISMが解説【IDC2023】 GO!

前回のコメント

・配列の要素数を12から24にかえるだけで少し混乱した。

 配列を使いこなすことで、データ量が大きいゲーム等の記述が可能になります。
 是非、使いこなしてください。

・課題がわからなかったです
・アレンジ演習でヒントをみても解く事が出来なかった

 少し難しかったですね。しっかりフォローしますので、理解を深めてください。

講義メモ:後半

p.142 3次元以上の配列

・C#では次元数の制限はない
・3次元配列の宣言の書式: データ型[,,] 配列名;
・3次元配列の要素の生成の書式: 配列名 = new データ型[要素数①, 要素数②, 要素数③];
・宣言と要素の生成は同時に行うことができる
 書式: データ型[,,] 配列名 = new データ型[要素数①, 要素数②, 要素数③];
・3次元配列では、要素の利用には3つの添字が必要
・よって、for文による繰り返しを3重化すると良い
・例:
 string[,,] names = new string[2, 3, 4]; //2種族各3グループ各4匹のモンスター名
 for (int i = 0; i < 2; i++) { //2種族の分、繰返す
  for (int j = 0; j < 3; j++) { //各3グループの分、繰返す
   for (int k = 0; j < 4; j++) { //各4匹の分、繰返す
    name[i, j, k] = Console.ReadLine();
   }
  }
 }
・初期値を列挙することによる初期化が可能
・3次元配列初期化の書式: 型[,,] 配列名 = { { {値,…}, … }, … }
・例: int[,] n = {{{1,2,3,4},{5,6,7,8},{9,10,11,12}},{{13,14,15,16},{17,18,19,20},{21,22,23,24}}};
・要素数は省略できるが「●×■×▲」の形式になる必要がある

p.142(次元数と要素数の取得)

・配列の次元数は「配列名.Rank」で得られる
・配列の全要素数は多次元配列においても「配列名.Length」で得られる
・C/C++等にように、多次元配列で「配列名[添字].Length」で上位要素数を得ることはできない

p.143 array04.cs

//p.143 array04.cs
using System;
class array04 {
    public static void Main() {
        int[,,] ar = new int[2, 2, 3] { //「new int[2, 2, 3]」は省略可
            {
                {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 < 2; i++) { //1番目の添字
            for (int j = 0; j < 2; j++) { //2番目の添字
                for (int k = 0; k < 3; k++) { //3番目の添字
                    Console.Write("{0}, ", ar[i, j, k]); //順に表示
                }
            }
        }
        Console.WriteLine(); //改行
    }
}

アレンジ演習:p.143 array04.cs

・4次元配列[2,2,2,3]にしよう

作成例

//アレンジ演習:p.143 array04.cs
using System;
class array04 {
    public static void Main() {
        int[,,,] ar = { //「new int[2, 2, 2, 3]」を省略
            { 
                { {0, 1, 2},{3,  4,  5} },
                { {6, 7, 8},{9, 10, 11} },
            },
            {
                { {0, 1, 2},{3,  4,  5} },
                { {6, 7, 8},{9, 10, 11} }, 
            }
        }; 
        Console.WriteLine("配列の次元 = {0}", ar.Rank); //次元数を表示
        Console.WriteLine("arの個数 = {0}", ar.Length); //要素数を表示
        for (int i = 0; i < 2; i++) { //1番目の添字
            for (int j = 0; j < 2; j++) { //2番目の添字
                for (int k = 0; k < 2; k++) { //3番目の添字
                    for (int l = 0; l < 3; l++) { //4番目の添字
                        Console.Write("{0}, ", ar[i, j, k, l]); //順に表示
                    }
                }
            }
        }
        Console.WriteLine(); //改行
    }
}

p.144 ジャグ配列

・C#における多次元配列のもう一つの様式で、配列の配列によって多次元配列を表す
・通常の多次元配列より記述が煩雑になるが、内側の要素数の異なる多次元配列を構築できるので、メモリの無駄を省くことができる
・以下は2次元のジャグ配列の場合:
・「[,]」ではなく、C/C++/Java等と同様に「[][]」で表す
・ジャグ配列の例:a[0][0] a[0][1] a[1][0] a[2][0] a[2][1] a[2][2]
・ジャグ配列の宣言の書式: データ型[][] 配列名;
・ジャグ配列の要素の生成の書式: 
 配列名 = new データ型[要素数①][]; 
 配列名[0] = new データ型[要素数②]; 配列名[1] = new データ型[要素数③]; … 
・初期値を列挙することによる初期化が可能
・ジャグ配列初期化の書式: 
 配列名 = new データ型[要素数①][]; 
 配列名[0] = new データ型[要素数②]{値,…}; 配列名[1] = new データ型[要素数③]{値,…}; … 
・「●×■」の形式になる必要はない
・配列の全要素数はジャグ配列においては「配列名.Length」では得られず、構成する配列数になる
・「配列名[添字].Length」で各配列の要素数が得られる

p.144 jagged01.cs

//p.144 jagged01.cs
using System;
class jagged01 {
    public static void Main() {
        int[][] ar; //(2次元)ジャグ配列の宣言
        ar = new int[2][]; //上位次元の要素数=含む配列の数は2
        ar[0] = new int[3]; //下位次元の要素数=含まれる配列①の要素数は3
        ar[1] = new int[3]; //下位次元の要素数=含まれる配列②の要素数は3
        //下記の※は含まれる2配列の要素数がどちらも3だから可能だが、そうとは限らない
        for (int i = 0; i < 2; i++) { //上位次元の要素数=含む配列の数だけ繰返す
            for (int j = 0; j < 3; j++) { //下位次元の要素数=含まれる配列の要素数だけ繰返す(※)
                ar[i][j] = (i + 1) * (j + 1); //要素に値を代入
            }
        }
        for (int i = 0; i < 2; i++) { //上位次元の要素数=含む配列の数だけ繰返す
            for (int j = 0; j < 3; j++) { //下位次元の要素数=含まれる配列の要素数だけ繰返す(※)
                Console.WriteLine("ar[{0}][{1}] = {2}", i, j, ar[i][j]);
            }
        }
    }
}

p.146 jagged02.cs

//p.146 jagged02.cs
using System;
class jagged02 {
    public static void Main() {
        string[][] name = new string[2][]; //(2次元)ジャグ配列の宣言と上位次元の要素数=含む配列の数は2の指定
        name[0] = new string[2]{"田中", "工藤"}; //含まれる配列①の初期化(2要素)
        name[1] = new string[3]{"吉田", "佐藤", "池田"}; //含まれる配列②の初期化(3要素)
        for (int i = 0; i < name[0].Length; i++) { //含まれる配列①の要素数について繰返す
            Console.WriteLine(name[0][i]); //含まれる配列①の要素を表示
        }
        for (int i = 0; i < name[1].Length; i++) { //含まれる配列②の要素数について繰返す
            Console.WriteLine(name[1][i]); //含まれる配列①の要素を表示
        }
    }
}

提出:アレンジ演習:p.146 jagged02.cs

・2つあるforを2重ループにして見やすくしよう
・ヒント:下記の●を0から1まで繰返せばよい
        for (int j = 0; j < name[●].Length; j++) { //含まれる配列の要素数について繰返す
            Console.WriteLine(name[●][j]); //含まれる配列の要素を表示
        }

講義メモ

・p.137「2次元配列」から

提出フォロー:アレンジ演習:p.136 average02.cs

・配列の3要素の値をコンソールから入力するようにしよう
・ヒント① 配列の初期化ではなく宣言と生成にする 
 例:int[] point = new int[3];
・ヒント② コンソールからの入力は繰返しの中(sumに足し込む前)で行うと良い
・ヒント③ 配列の要素は変数と同様に扱えるので、コンソールからの入力を要素に代入する
 例:Console.Write("{0}番:", i); point[i] = int.Parse(Console.ReadLine());

作成例

//アレンジ演習:p.136 average02.cs
using System;
class average02 {
    public static void Main() {
        int[] point = new int[3]; //【変更】int型の配列pointを3要素で生成
        int sum = 0, no; //合計、要素数
        no = point.Length; //プロパティで配列の要素数を得る
        for (int i = 0; i < no; i++) { //iを0から要素数未満まで=全要素について繰返す
            Console.Write("{0}番:", i); point[i] = int.Parse(Console.ReadLine());
            sum += point[i]; //i番の要素の値をsumに足し込む
        }
        double average = (double)sum / no; //合計を件数で割って平均値を得る
        Console.WriteLine("合計 = {0}, 平均 = {1:##.#}", sum, average); //合計値と平均値(小数点以下1桁)を表示
    }
}

アレンジ演習:p.136 average02.cs・続き

・入力された値を逆順にしよう
例:10,20,30ならば30,20,10にする
・2つ方法があり、どちらでもOK
 ①入力時に末尾の要素から格納
 ②全て格納してから反転する

作成例①

//アレンジ演習:p.136 average02.cs・続き ①入力時に末尾の要素から格納
using System;
class average02 {
    public static void Main() {
        int[] point = new int[3]; //int型の配列pointを3要素で生成
        int sum = 0, no; //合計、要素数
        no = point.Length; //プロパティで配列の要素数を得る
        for (int i = no - 1; i >= 0; i--) { //【変更】iを末尾から0まで=全要素について繰返す
            Console.Write("{0}番:", i); point[i] = int.Parse(Console.ReadLine());
            sum += point[i]; //i番の要素の値をsumに足し込む
        }
        double average = (double)sum / no; //合計を件数で割って平均値を得る
        Console.WriteLine("合計 = {0}, 平均 = {1:##.#}", sum, average); //合計値と平均値(小数点以下1桁)を表示
        for (int i = 0; i < no; i++) { //【以下追加】iを0から要素数未満まで=全要素について繰返す
            Console.WriteLine("{0}番:{1}", i, point[i]);
        }
    }
}

作成例②

//アレンジ演習:p.136 average02.cs・続き ②全て格納してから反転
using System;
class average02 {
    public static void Main() {
        int[] point = new int[3]; //int型の配列pointを3要素で生成
        int sum = 0, no; //合計、要素数
        no = point.Length; //プロパティで配列の要素数を得る
        for (int i = 0; i < no; i++) { //iを0から要素数未満まで=全要素について繰返す
            Console.Write("{0}番:", i); point[i] = int.Parse(Console.ReadLine());
            sum += point[i]; //i番の要素の値をsumに足し込む
        }
        double average = (double)sum / no; //合計を件数で割って平均値を得る
        Console.WriteLine("合計 = {0}, 平均 = {1:##.#}", sum, average); //合計値と平均値(小数点以下1桁)を表示
        int work = point[0]; point[0] = point[2]; point[2] = work; //【以下追加】要素[0]と[2]の値を交換する
        for (int i = 0; i < no; i++) { //iを0から要素数未満まで=全要素について繰返す
            Console.WriteLine("{0}番:{1}", i, point[i]);
        }
    }
}

p.137 2次元配列

・添字を2つ以上持つ配列を多次元配列といい、2つの場合は2次元配列
・ゲームのマップや行列型の情報の扱いに向いている
・C#には多次元配列の実装方法が2種類あり、他の言語とは異なるので注意
・配列に格納されるデータを要素という
・(通常型の)2次元配列は2つの添え字の数の積の要素が格納できる
・例:添字①が2、添字②が5であれば2×5=10要素分になる(p.137 表6.1)
・配列は変数とは異なり、配列名の宣言の後で、要素の生成を行うと利用可能になる
・宣言の書式: データ型[,] 配列名;
・要素の生成の書式: 配列名 = new データ型[要素数①, 要素数②];
・宣言と要素の生成は同時に行うことができる
 書式: データ型[,] 配列名 = new データ型[要素数①, 要素数②];
・例: int[,] MonsterMap = new int[100, 100]; //100×100のマップの部屋ごとのモンスター数
・2次元配列なので、要素の利用には2つの添字が必要
・よって、for文による繰り返しを2重化すると良い
・例:
 string[,] names = new string[2, 3]; //2種族3匹のモンスター名
 for (int i = 0; i < 2; i++) { //2種族の分、繰返す
  for (int j = 0; j < 3; j++) { //各3匹の分、繰返す
   name[i,j] = Console.ReadLine();
  }
 }

p.138 array01.cs

//p.138 array01.cs
using System;
class array01 {
    public static void Main() {
        int[,] MyArray = new int[2,3]; //2×3の2次元配列を生成
        int i, j; //繰返し&添字用
        MyArray[0, 0] = 1; //要素に値を代入
        MyArray[0, 1] = 2; //  〃
        MyArray[0, 2] = 3; //  〃
        MyArray[1, 0] = 4; //  〃
        MyArray[1, 1] = 5; //  〃
        MyArray[1, 2] = 6; //  〃
        for (i = 0; i < 2; i++) { //添字①の数だけ繰返す
            for (j = 0; j < 3; j++) { //添字②の数だけ繰返す
                Console.WriteLine("MyArray[{0}, {1}] = {2}",i, j, MyArray[i, j]);
            }
        }
    }
}

アレンジ演習:p.138 array01.cs

・コンソールから添字①、添字②、値を入力するようにしよう
・「続ける(y/n)」と表示してyが入力されている間、上記を繰返し、y以外が入力されたら全データを表示しよう
【発展課題】範囲を超える添字①②が入力されたら再入力させる
ヒント:「yが入力されている間」も「再入力させる」もdo-whileでループすると良い

作成例

//アレンジ演習:p.138 array01.cs
using System;
class array01 {
    public static void Main() {
        int[,] MyArray = new int[2,3]; //2×3の2次元配列を生成
        int i, j; //繰返し&添字用
        string ans = "";
        do {
            Console.Write("添字①:"); i = int.Parse(Console.ReadLine());
            Console.Write("添字②:"); j = int.Parse(Console.ReadLine());
            Console.Write("値:"); MyArray[i, j] = int.Parse(Console.ReadLine()); //要素に格納
            Console.Write("続ける(y/n):"); ans = Console.ReadLine();
        } while (ans == "y");
        for (i = 0; i < 2; i++) { //添字①の数だけ繰返す
            for (j = 0; j < 3; j++) { //添字②の数だけ繰返す
                Console.WriteLine("MyArray[{0}, {1}] = {2}",i, j, MyArray[i, j]);
            }
        }
    }
}

作成例【発展課題】

//アレンジ演習:p.138 array01.cs
using System;
class array01 {
    public static void Main() {
        int[,] MyArray = new int[2,3]; //2×3の2次元配列を生成
        int i, j; //繰返し&添字用
        string ans = "";
        do { //入力の繰返し
            do { //添字①入力の繰返し
                Console.Write("添字①:"); 
                i = int.Parse(Console.ReadLine());
            } while (i >= 2); //2以上ならやりなおし
            do { //添字②入力の繰返し
                Console.Write("添字②:"); 
                j = int.Parse(Console.ReadLine());
            } while (j >= 3); //3以上ならやりなおし
            Console.Write("値:"); MyArray[i, j] = int.Parse(Console.ReadLine()); //要素に格納
            Console.Write("続ける(y/n):"); ans = Console.ReadLine();
        } while (ans == "y");
        for (i = 0; i < 2; i++) { //添字①の数だけ繰返す
            for (j = 0; j < 3; j++) { //添字②の数だけ繰返す
                Console.WriteLine("MyArray[{0}, {1}] = {2}",i, j, MyArray[i, j]);
            }
        }
    }
}

p.138(2次元配列の初期化)

・1次元配列と同様に、初期値を列挙することによる初期化が可能
・書式: 型[,] 配列名 = { {値,…}, … }
・例: string[,] names = { {"ヴェルドラ", "ヴェルグリンド"}, {"リムル, "シュナ"} }; //2×2の配列
・要素数は省略できるが「●×■」の形式になる必要がある
・例:
 int[,] MyArray = {{1, 2, 3}, {4, 5}}; //エラーになる
 int[,] MyArray = new int[2, 3]{{1, 2, 3}, {4, 5}}; //エラーになる
 ※テキストp.139の下から4行目の「初期値が設定されていない要素は0で初期化」は誤り

p.139 array02.cs

//p.139 array02.cs
using System;
class array02
{
    public static void Main()
    {
        int[,] MyArray = {{1, 2, 3}, {4, 5, 6}}; //初期化で2×3の配列になる
        for (int i = 0; i < 2; i++) { //添字①の数だけ繰返す
            for (int j = 0; j < 3; j++) { //添字②の数だけ繰返す
                Console.WriteLine("MyArray[{0}, {1}] = {2}", i, j, MyArray[i, j]);
            }
        }
    }
}

p.140 array03.csについて

・このプログラムでは入力チェックを3段階行っている
 ① 文字数が2以上ではないか
 ② 先頭文字が数字以外ではないか
 ③ 範囲は正しいか(クラスは1~2、出席番号は1~5)
・この②で用いているのが、Char.IsNumber(文字列, n番目)で、先頭を0番目として数えたn番目の文字が数字かどうかを返す。
・Charはcharの.NET型で、文字を扱う構造体(第11章にて後述)として提供されている。IsNumberはこれに含まれるメソッド。
・また、③で用いているのが、Int32.Parse(文字列)で、これは、int.Parse(文字列)と同じ意味
・continueについてはp.130参照

p.140 array03.cs

//p.140 array03.cs
using System;
class array03 {
    public static void Main() {
        string[,] Name = new string[2, 5] { //2×5要素の文字列の配列
                {"田中六郎", "吉田一郎", "太田太郎", "粂井康孝", "岡田三郎"},
                {"横田芳子", "池田和子", "目黒貴和子", "武田信子", "園田淳子"}
        };
        int MyClass, No; //組と出席番号
        string strClass, strNo; //組と出席番号(入力用)
        while (true) { //無限ループ
            Console.Write("クラスは---");
            strClass = Console.ReadLine();
            if (strClass.Length >= 2) { //2文字以上が入力された?
                Console.WriteLine("入力は1桁のみです");
                continue; //以降をスキップして繰返し続行
            }
            if (Char.IsNumber(strClass, 0) != true) { //1文字目は数字か?
                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) { //2文字以上が入力された?
                Console.WriteLine("入力は1桁のみです");
                continue; //以降をスキップして繰返し続行
            }
            if (Char.IsNumber(strNo, 0) != true) { //1文字目は数字か?
                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]);
    }
}