C#の二次元配列とは?宣言・初期化・要素の取得まで初心者向けに解説

はじめに

C#で表形式のデータやゲームの盤面を扱うときに役立つのが、二次元配列です。二次元配列を使うと、複数の値を「行」と「列」に分けて整理できます。

たとえば、3人分の3教科の点数を管理する場合、一次元配列だけではデータ同士の関係が分かりにくくなります。二次元配列なら、行を生徒、列を教科として扱えるため、表に近い形でデータを管理できます。

この記事では、C#の二次元配列について、宣言、初期化、要素の取得、for文による繰り返し処理まで初心者向けに解説します。ジャグ配列やListとの違い、よくあるエラーについても確認していきましょう。

1. C#の二次元配列とは?

1-1. 二次元配列は「行」と「列」でデータを管理する配列

C#の二次元配列とは、データを行と列の組み合わせで管理する配列です。

たとえば、次のような表を考えてみましょう。

生徒国語数学英語
Aさん807590
Bさん658872

この表は、2行3列の二次元配列として表現できます。

int[,] scores ={{ 80, 75, 90 },{ 65, 88, 72 }};

int[,]に含まれるカンマは、この配列が二次元であることを表しています。

最初の行にはAさんの点数、2番目の行にはBさんの点数が格納されています。それぞれの行には、国語、数学、英語の点数が列として並んでいます。

1-2. 一次元配列との違い

一次元配列は、値が一直線に並ぶ配列です。

int[] numbers = { 10, 20, 30 };

各要素には、1つのインデックスを指定してアクセスします。

Console.WriteLine(numbers[1]); // 20

一方、二次元配列では、行番号と列番号の2つを指定します。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

Console.WriteLine(numbers[1, 2]); // 60

numbers[1, 2]は、インデックスが1の行と、インデックスが2の列が交差する要素を表します。

一次元配列がリストのような構造であるのに対し、二次元配列は表のような構造であると考えると分かりやすいでしょう。

1-3. 二次元配列が使われる主な場面

C#の二次元配列は、次のような場面で利用できます。

  • 生徒ごと、教科ごとの点数表

  • 映画館や電車の座席表

  • オセロや将棋などのゲーム盤面

  • 商品ごと、月ごとの売上表

  • 画像を構成するピクセルデータ

  • 縦横に並んだマップデータ

行数と列数が決まっている表形式のデータは、二次元配列と相性がよいデータです。

1-4. C#で二次元配列を扱うときの基本イメージ

二次元配列の要素には、次の形式でアクセスします。

配列名[行番号, 列番号]

たとえば、次の二次元配列があるとします。

int[,] data ={{ 10, 20 },{ 30, 40 },{ 50, 60 }};

各要素の位置は次のようになります。

data[0, 0]  data[0, 1]data[1, 0]  data[1, 1]data[2, 0]  data[2, 1]

C#の配列インデックスは0から始まります。そのため、3行2列の配列で使用できる行番号は0から2、列番号は0から1です。

2. C#の二次元配列の宣言方法

2-1. 二次元配列の基本構文

C#で二次元配列を宣言する基本構文は、次のとおりです。

データ型[,] 配列名;

整数を格納する二次元配列ならint[,]、文字列を格納する二次元配列ならstring[,]と記述します。

int[,] numbers;string[,] names;

この時点では、配列を格納する変数を宣言しただけです。実際に要素を格納する領域は、まだ作成されていません。

2-2. int型の二次元配列を宣言する例

int型の二次元配列は、次のように宣言できます。

int[,] scores;

宣言と同時に配列の領域を確保する場合は、newを使います。

int[,] scores = new int[3, 4];

このコードでは、3行4列の二次元配列を作成しています。格納できる要素数は、3×4で合計12個です。

2-3. string型の二次元配列を宣言する例

文字列を格納する場合は、string[,]を使用します。

string[,] seats = new string[2, 3];

この配列は2行3列です。

値を代入する場合は、次のように行番号と列番号を指定します。

seats[0, 0] = "予約済み";seats[0, 1] = "空席";seats[0, 2] = "予約済み";

string型の配列を作成した直後は、それぞれの要素にnullが格納されています。

2-4. 宣言だけ行う場合と同時に領域を確保する場合の違い

次のコードは、変数を宣言しただけです。

int[,] scores;

ローカル変数として宣言した場合、値を代入する前に使用するとコンパイルエラーになります。

int[,] scores;

// コンパイルエラー// Console.WriteLine(scores[0, 0]);

次のコードでは、宣言と同時に3行4列の領域を確保しています。

int[,] scores = new int[3, 4];

配列の領域が作成されているため、要素の取得や代入が可能です。

宣言と領域の確保を分けることもできます。

int[,] scores;scores = new int[3, 4];

処理の途中で配列のサイズを決める場合には、この書き方を利用できます。

3. C#の二次元配列を初期化する方法

3-1. newを使って要素数を指定する方法

二次元配列を作成するときは、newの後ろに行数と列数を指定します。

int[,] numbers = new int[2, 3];

このコードでは、2行3列の配列が作成されます。

[0, 0] [0, 1] [0, 2][1, 0] [1, 1] [1, 2]

要素数を変数で指定することも可能です。

int rowCount = 4;int columnCount = 5;

int[,] numbers = new int[rowCount, columnCount];

行数や列数が実行時に決まる場合に便利です。

3-2. 宣言と同時に値を入れて初期化する方法

二次元配列には、宣言と同時に値を設定できます。

int[,] numbers = new int[,]{{ 10, 20, 30 },{ 40, 50, 60 }};

型と値から配列のサイズを判断できるため、new int[,]を省略することもできます。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

この配列は2行3列です。

文字列も同様に初期化できます。

string[,] members ={{ "田中", "営業部" },{ "佐藤", "開発部" },{ "鈴木", "総務部" }};

初期化子を使用する場合、すべての行の列数をそろえる必要があります。

3-3. 後から要素に値を代入する方法

配列を作成した後で、各要素に値を代入できます。

int[,] numbers = new int[2, 3];

numbers[0, 0] = 10;numbers[0, 1] = 20;numbers[0, 2] = 30;numbers[1, 0] = 40;numbers[1, 1] = 50;numbers[1, 2] = 60;

値を上書きする場合も、同じ書き方を使用します。

numbers[0, 1] = 99;

これにより、numbers[0, 1]の値は20から99に変更されます。

3-4. 初期化しない場合の既定値

newで配列を作成すると、各要素にはデータ型に応じた既定値が自動的に設定されます。

主な既定値は次のとおりです。

データ型既定値
int0
double0.0
boolfalse
char'\0'
stringnull
その他の参照型null

たとえば、次の配列の要素はすべて0です。

int[,] numbers = new int[2, 3];

Console.WriteLine(numbers[0, 0]); // 0Console.WriteLine(numbers[1, 2]); // 0

int型の配列については、すべての要素に0を代入する処理を自分で書く必要はありません。

3-5. 初期化時によくあるエラー

初期化時によくある間違いは、行ごとの列数を変えてしまうことです。

// コンパイルエラーint[,] numbers ={{ 10, 20 },{ 30, 40, 50 }};

二次元配列は長方形の構造を持つため、すべての行に同じ数の要素が必要です。

次のように列数をそろえれば初期化できます。

int[,] numbers ={{ 10, 20, 0 },{ 30, 40, 50 }};

行ごとに異なる数の要素を格納したい場合は、二次元配列ではなくジャグ配列を検討します。

4. C#の二次元配列から要素を取得・変更する方法

4-1. 要素を取得する基本構文

二次元配列から要素を取得する基本構文は、次のとおりです。

配列名[行番号, 列番号]

具体例を見てみましょう。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

int value = numbers[1, 2];

Console.WriteLine(value); // 60

numbers[1, 2]は、2行目の3列目にある60を表します。

4-2. 行番号と列番号の考え方

角括弧内の最初の数値が行番号、次の数値が列番号です。

numbers[行番号, 列番号]

次の配列で位置を確認してみましょう。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

各値の位置は次のとおりです。

要素の位置
10numbers[0, 0]
20numbers[0, 1]
30numbers[0, 2]
40numbers[1, 0]
50numbers[1, 1]
60numbers[1, 2]

「縦方向が行、横方向が列」と覚えると理解しやすくなります。

4-3. 要素の値を変更する方法

二次元配列の要素を変更する場合は、変更したい位置を指定して新しい値を代入します。

int[,] numbers ={{ 10, 20 },{ 30, 40 }};

numbers[0, 1] = 99;

Console.WriteLine(numbers[0, 1]); // 99

配列のサイズは変更できませんが、各要素の値は何度でも変更できます。

4-4. インデックスは0から始まる点に注意

C#の配列インデックスは0から始まります。

たとえば、3行4列の配列を作成した場合、使用できるインデックスは次のとおりです。

  • 行番号:0、1、2

  • 列番号:0、1、2、3

int[,] numbers = new int[3, 4];

numbers[0, 0] = 10;numbers[2, 3] = 20;

最後の要素はnumbers[3, 4]ではなく、numbers[2, 3]です。

4-5. 範囲外アクセスで発生するエラー

配列の範囲外にアクセスすると、IndexOutOfRangeExceptionが発生します。

int[,] numbers = new int[2, 3];

// 行番号2は範囲外Console.WriteLine(numbers[2, 0]);

2行の配列で使用できる行番号は0と1だけです。行番号2を指定すると範囲外になります。

列番号についても同様です。

int[,] numbers = new int[2, 3];

// 列番号3は範囲外Console.WriteLine(numbers[0, 3]);

配列の行数と列数を確認し、範囲内のインデックスを指定する必要があります。

5. C#の二次元配列をfor文で処理する方法

5-1. ネストしたfor文で全要素を取得する

二次元配列の全要素を順番に取得するには、for文を2つ組み合わせます。このような構造を、ネストしたfor文または二重ループと呼びます。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

for (int row = 0; row < 2; row++){for (int column = 0; column < 3; column++){Console.WriteLine(numbers[row, column]);}}

外側のfor文で行を進め、内側のfor文で各行の列を進めています。

ただし、行数や列数をコードに直接書くと、配列のサイズを変更したときにfor文も修正しなければなりません。通常はGetLengthを使用します。

5-2. GetLengthで行数・列数を取得する

二次元配列の行数と列数は、GetLengthメソッドで取得できます。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

int rowCount = numbers.GetLength(0);int columnCount = numbers.GetLength(1);

Console.WriteLine(rowCount); // 2Console.WriteLine(columnCount); // 3

GetLength(0)は1つ目の次元、つまり行数を返します。GetLength(1)は2つ目の次元、つまり列数を返します。

全要素を処理する場合は、次のように記述します。

for (int row = 0; row < numbers.GetLength(0); row++){for (int column = 0; column < numbers.GetLength(1); column++){Console.WriteLine(numbers[row, column]);}}

配列の大きさが変わっても、そのまま利用できる書き方です。

5-3. 二次元配列の中身を一覧表示するサンプル

各要素の位置と値を表示するサンプルです。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

for (int row = 0; row < numbers.GetLength(0); row++){for (int column = 0; column < numbers.GetLength(1); column++){Console.WriteLine($"numbers[{row}, {column}] = {numbers[row, column]}");}}

実行結果は次のようになります。

numbers[0, 0] = 10numbers[0, 1] = 20numbers[0, 2] = 30numbers[1, 0] = 40numbers[1, 1] = 50numbers[1, 2] = 60

インデックスと値を一緒に表示すると、行と列の関係を確認しやすくなります。

5-4. foreach文で二次元配列を処理する場合の注意点

二次元配列は、foreach文でも処理できます。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

foreach (int number in numbers){Console.WriteLine(number);}

実行結果は次のようになります。

102030405060

foreach文は全要素を簡単に取得できる一方、現在の要素が何行目、何列目にあるのかを直接取得できません。

また、foreachの反復変数に値を代入して配列要素を変更することもできません。

foreach (int number in numbers){// number = 0; は記述できない}

行番号と列番号が必要な処理や、要素を変更する処理では、ネストしたfor文を使うのが適しています。

5-5. 表形式で出力するサンプルコード

二次元配列を表形式で出力するには、内側のfor文では改行せず、1行分の処理が終わった後に改行します。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 },{ 70, 80, 90 }};

for (int row = 0; row < numbers.GetLength(0); row++){for (int column = 0; column < numbers.GetLength(1); column++){Console.Write($"{numbers[row, column],4}");}

Console.WriteLine();

}

実行結果は次のようになります。

  10  20  3040  50  6070  80  90

{値,4}は、値を4文字分の幅で右寄せして表示する指定です。桁数が異なる数値でも、列をそろえて見やすく出力できます。

6. C#の二次元配列でよく使う実践サンプル

6-1. 点数表を二次元配列で管理する

3人分の国語、数学、英語の点数を管理する例です。

string[] studentNames = { "田中", "佐藤", "鈴木" };string[] subjectNames = { "国語", "数学", "英語" };

int[,] scores ={{ 80, 75, 90 },{ 65, 88, 72 },{ 92, 81, 85 }};

for (int row = 0; row < scores.GetLength(0); row++){Console.WriteLine($"{studentNames[row]}さんの点数");

for (int column = 0; column &lt; scores.GetLength(1); column++){Console.WriteLine($"{subjectNames<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[column]</span>}: {scores<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[row, column]</span>}点");}Console.WriteLine();

}

この例では、二次元配列の行番号と生徒名の配列、列番号と教科名の配列を対応させています。

6-2. 座席表を二次元配列で管理する

座席の予約状況をbool型の二次元配列で管理する例です。

bool[,] reservedSeats = new bool[3, 4];

reservedSeats[0, 1] = true;reservedSeats[1, 3] = true;reservedSeats[2, 0] = true;

for (int row = 0; row < reservedSeats.GetLength(0); row++){for (int column = 0; column < reservedSeats.GetLength(1); column++){string status = reservedSeats[row, column]? "予約済み": "空席";

    Console.Write($"<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[{status}]</span>");}Console.WriteLine();

}

bool型の既定値はfalseなので、配列を作成した直後はすべて空席として扱えます。予約された座席だけをtrueに変更しています。

6-3. 盤面ゲームを二次元配列で表現する

3×3のゲーム盤面を表現する例です。

char[,] board ={{ 'O', 'X', 'O' },{ 'X', 'O', ' ' },{ 'X', ' ', 'O' }};

for (int row = 0; row < board.GetLength(0); row++){for (int column = 0; column < board.GetLength(1); column++){Console.Write($" {board[row, column]} ");

    if (column &lt; board.GetLength(1) - 1){Console.Write("|");}}Console.WriteLine();if (row &lt; board.GetLength(0) - 1){Console.WriteLine("---+---+---");}

}

実行結果は次のようになります。

 O | X | O---+---+---X | O |
---+---+---X | | O

盤面の縦横サイズが固定されているゲームでは、二次元配列を使うと各マスの状態を直感的に管理できます。

6-4. 文字列データを二次元配列で扱う

社員名と部署名を二次元配列で管理する例です。

string[,] employees ={{ "田中", "営業部" },{ "佐藤", "開発部" },{ "鈴木", "総務部" }};

for (int row = 0; row < employees.GetLength(0); row++){string name = employees[row, 0];string department = employees[row, 1];

Console.WriteLine($"{name}さん:{department}");

}

実行結果は次のようになります。

田中さん:営業部佐藤さん:開発部鈴木さん:総務部

ただし、社員情報のように項目の意味が異なるデータを本格的に管理する場合は、クラスやレコードを定義したほうが分かりやすくなることがあります。

6-5. 合計値や平均値を計算する

二次元配列に格納されたすべての点数から、合計値と平均値を計算する例です。

int[,] scores ={{ 80, 75, 90 },{ 65, 88, 72 },{ 92, 81, 85 }};

int total = 0;

for (int row = 0; row < scores.GetLength(0); row++){for (int column = 0; column < scores.GetLength(1); column++){total += scores[row, column];}}

double average = (double)total / scores.Length;

Console.WriteLine($"合計: {total}");Console.WriteLine($"平均: {average:F1}");

scores.Lengthは、二次元配列に含まれる全要素数を返します。この例では3行3列なので、値は9です。

特定の行だけの平均を求める場合は、次のように計算できます。

int targetRow = 0;int rowTotal = 0;

for (int column = 0; column < scores.GetLength(1); column++){rowTotal += scores[targetRow, column];}

double rowAverage =(double)rowTotal / scores.GetLength(1);

Console.WriteLine($"1人目の平均: {rowAverage:F1}");

7. 二次元配列とジャグ配列・Listの違い

7-1. 多次元配列とジャグ配列の違い

C#で表形式のデータを扱う方法には、二次元配列だけでなくジャグ配列もあります。

二次元配列は、すべての行が同じ列数を持つ長方形の配列です。

int[,] numbers ={{ 1, 2, 3 },{ 4, 5, 6 }};

ジャグ配列は、配列の各要素に別の配列を格納する構造です。行ごとに異なる数の要素を持てます。

int[][] numbers ={new int[] { 1, 2 },new int[] { 3, 4, 5 },new int[] { 6 }};

ジャグ配列は「配列の配列」とも呼ばれます。

7-2. int[,]とint[][]の書き方の違い

二次元配列とジャグ配列では、宣言方法と要素へのアクセス方法が異なります。

二次元配列はint[,]と宣言します。

int[,] matrix = new int[2, 3];

matrix[0, 1] = 10;

ジャグ配列はint[][]と宣言します。

int[][] jagged = new int[2][];

jagged[0] = new int[3];jagged[1] = new int[2];

jagged[0][1] = 10;

要素へのアクセス方法は次のように異なります。

matrix[0, 1];  // 二次元配列jagged[0][1];  // ジャグ配列

二次元配列は1組の角括弧に行番号と列番号を指定し、ジャグ配列は角括弧を2回使用します。

7-3. 二次元配列とList<List>の違い

List<List<T>>を使っても、行と列を持つデータ構造を作れます。

List<List<int>> numbers = new List<List<int>>{new List<int> { 1, 2, 3 },new List<int> { 4, 5, 6 }};

要素には次のようにアクセスします。

Console.WriteLine(numbers[1][2]); // 6

二次元配列と異なり、ListはAddRemoveを使って要素数を変更できます。

numbers[0].Add(100);numbers.Add(new List<int> { 7, 8, 9 });

ただし、行ごとの要素数が簡単に変えられるため、長方形の構造を維持したい場合には注意が必要です。

7-4. 要素数が固定なら二次元配列が向いている

行数と列数が最初から決まっており、処理中にサイズを変更しない場合は、二次元配列が適しています。

たとえば、次のようなデータです。

  • 8×8マスのゲーム盤

  • 12か月分の商品別売上

  • 固定された教室の座席表

  • 縦横サイズが決まった画像データ

配列名[行, 列]という書き方で要素の位置を明確に表せるため、表形式の処理を記述しやすい点がメリットです。

7-5. 要素数が変わるならListが向いている

処理中に行や要素を追加、削除する必要がある場合は、Listが適しています。

List<List<string>> groups = new List<List<string>>();

groups.Add(new List<string> { "田中", "佐藤" });groups.Add(new List<string> { "鈴木" });

groups[1].Add("高橋");

データ数が頻繁に変化する場合、固定長の二次元配列では、新しい配列を作成してデータをコピーする必要があります。ListならAddRemoveを使って柔軟に変更できます。

8. C#の二次元配列で初心者がつまずきやすいポイント

8-1. 配列のサイズは後から変更できない

C#の配列は固定長です。一度作成した二次元配列の行数や列数を、後から変更することはできません。

int[,] numbers = new int[2, 3];

この配列を3行4列に拡張することはできません。サイズを変更したい場合は、新しい配列を作成して必要な値をコピーします。

int[,] oldNumbers ={{ 1, 2, 3 },{ 4, 5, 6 }};

int[,] newNumbers = new int[3, 4];

for (int row = 0; row < oldNumbers.GetLength(0); row++){for (int column = 0;column < oldNumbers.GetLength(1);column++){newNumbers[row, column] =oldNumbers[row, column];}}

サイズ変更が頻繁に必要なら、Listやジャグ配列などの別のデータ構造も検討しましょう。

8-2. 行と列の順番を間違えやすい

二次元配列では、最初のインデックスが行、2番目のインデックスが列です。

numbers[行番号, 列番号]

次の配列は2行3列です。

int[,] numbers = new int[2, 3];

そのため、numbers[1, 2]にはアクセスできますが、numbers[2, 1]にはアクセスできません。

numbers[1, 2] = 10; // 正常

// 行番号2は範囲外// numbers[2, 1] = 10;

変数名にrowcolumnを使うと、順番を間違えにくくなります。

8-3. LengthとGetLengthの違い

Lengthは、配列全体の要素数を返します。

int[,] numbers = new int[2, 3];

Console.WriteLine(numbers.Length); // 6

GetLengthは、指定した次元の要素数を返します。

Console.WriteLine(numbers.GetLength(0)); // 2Console.WriteLine(numbers.GetLength(1)); // 3

それぞれの役割は次のとおりです。

書き方取得できる値
numbers.Length全要素数
numbers.GetLength(0)行数
numbers.GetLength(1)列数

ネストしたfor文では、通常GetLength(0)GetLength(1)を使用します。

8-4. NullReferenceExceptionが発生するケース

配列変数の値がnullの状態で要素へアクセスすると、NullReferenceExceptionが発生します。

int[,]? numbers = null;

// NullReferenceExceptionConsole.WriteLine(numbers[0, 0]);

アクセスする前に配列を作成する必要があります。

int[,] numbers = new int[2, 3];

Console.WriteLine(numbers[0, 0]); // 0

参照型を要素に持つ二次元配列にも注意が必要です。

string[,] names = new string[2, 2];

// names[0, 0]はnullConsole.WriteLine(names[0, 0].Length);

配列自体は作成されていますが、string型の各要素の初期値はnullです。nullの要素からLengthを取得しようとすると、NullReferenceExceptionが発生します。

names[0, 0] = "田中";

Console.WriteLine(names[0, 0].Length); // 2

8-5. IndexOutOfRangeExceptionが発生するケース

指定した行番号または列番号が配列の範囲を超えると、IndexOutOfRangeExceptionが発生します。

int[,] numbers = new int[2, 3];

// 使用できる行番号は0と1Console.WriteLine(numbers[2, 0]);

for文の終了条件を<=にしてしまうことも、よくある原因です。

int[,] numbers = new int[2, 3];

// 誤った例for (int row = 0; row <= numbers.GetLength(0); row++){Console.WriteLine(numbers[row, 0]);}

GetLength(0)が2の場合、最後に行番号2へアクセスしてエラーになります。

終了条件には<を使います。

for (int row = 0; row < numbers.GetLength(0); row++){Console.WriteLine(numbers[row, 0]);}

9. C#の二次元配列に関するよくある質問

9-1. 二次元配列に要素を追加できる?

作成済みの二次元配列に、行や列を直接追加することはできません。C#の配列は固定長だからです。

要素数を増やすには、より大きな配列を新しく作成し、元の配列から値をコピーします。

int[,] oldArray ={{ 1, 2 },{ 3, 4 }};

int[,] newArray = new int[3, 2];

for (int row = 0; row < oldArray.GetLength(0); row++){for (int column = 0;column < oldArray.GetLength(1);column++){newArray[row, column] =oldArray[row, column];}}

newArray[2, 0] = 5;newArray[2, 1] = 6;

行や列を頻繁に追加する場合は、List<List<T>>などを使用したほうが簡単です。

9-2. 二次元配列の行数・列数を取得するには?

GetLengthメソッドを使用します。

int[,] numbers = new int[4, 5];

int rowCount = numbers.GetLength(0);int columnCount = numbers.GetLength(1);

Console.WriteLine($"行数: {rowCount}");Console.WriteLine($"列数: {columnCount}");

GetLength(0)が行数、GetLength(1)が列数です。

配列の次元数そのものを取得する場合は、Rankプロパティを使用できます。

Console.WriteLine(numbers.Rank); // 2

二次元配列なので、Rankの値は2です。

9-3. 二次元配列を初期化後にすべて0に戻せる?

int型の二次元配列をすべて0に戻すには、Array.Clearを使用できます。

int[,] numbers ={{ 10, 20 },{ 30, 40 }};

Array.Clear(numbers, 0, numbers.Length);

実行後は、すべての要素がint型の既定値である0になります。

for (int row = 0; row < numbers.GetLength(0); row++){for (int column = 0;column < numbers.GetLength(1);column++){Console.WriteLine(numbers[row, column]);}}

Array.Clearは単純に0を代入する機能ではなく、各データ型の既定値へ戻す処理です。そのため、bool型ならfalse、string型ならnullになります。

9-4. 二次元配列をメソッドの引数に渡せる?

二次元配列は、メソッドの引数に渡せます。

static void PrintArray(int[,] numbers){for (int row = 0; row < numbers.GetLength(0); row++){for (int column = 0;column < numbers.GetLength(1);column++){Console.Write($"{numbers[row, column]} ");}

    Console.WriteLine();}

}

呼び出す側では、通常の変数と同じように配列を渡します。

int[,] numbers ={{ 1, 2, 3 },{ 4, 5, 6 }};

PrintArray(numbers);

メソッド内で要素を変更すると、呼び出し元の配列にも変更が反映されます。

static void SetFirstValue(int[,] numbers){numbers[0, 0] = 999;}

使用例は次のとおりです。

int[,] numbers ={{ 1, 2 },{ 3, 4 }};

SetFirstValue(numbers);

Console.WriteLine(numbers[0, 0]); // 999

9-5. 二次元配列と配列の配列はどちらを使うべき?

すべての行で列数が同じで、長方形の表として扱いたい場合は、int[,]のような二次元配列が適しています。

int[,] matrix = new int[3, 4];

行ごとに要素数が異なる場合は、int[][]のようなジャグ配列が適しています。

int[][] jagged ={new int[] { 1, 2 },new int[] { 3, 4, 5 },new int[] { 6 }};

選択の目安は次のとおりです。

データの特徴適した型
すべての行で列数が同じ二次元配列
行ごとに列数が異なるジャグ配列
要素数を頻繁に変更するList<List<T>>
位置を行と列で明確に表したい二次元配列

どちらが常に優れているというものではありません。扱うデータの形や、サイズ変更の必要性に応じて選びましょう。

まとめ

C#の二次元配列は、複数の値を行と列で管理するためのデータ構造です。点数表、座席表、ゲーム盤面など、縦横に並んだデータを扱う場面で活用できます。

二次元配列は、次のように宣言します。

int[,] numbers = new int[2, 3];

値を指定して初期化することもできます。

int[,] numbers ={{ 10, 20, 30 },{ 40, 50, 60 }};

要素を取得、変更するときは、行番号と列番号を指定します。

int value = numbers[1, 2];numbers[0, 1] = 99;

全要素を処理するときは、GetLengthとネストしたfor文を組み合わせるのが基本です。

for (int row = 0; row < numbers.GetLength(0); row++){for (int column = 0;column < numbers.GetLength(1);column++){Console.WriteLine(numbers[row, column]);}}

インデックスは0から始まり、配列のサイズは作成後に変更できません。Lengthは全要素数、GetLength(0)は行数、GetLength(1)は列数を返すという違いも覚えておきましょう。

行数と列数が固定された表形式のデータには二次元配列、行ごとに長さが異なるデータにはジャグ配列、要素数が頻繁に変わるデータにはListが適しています。それぞれの特徴を理解し、目的に合ったデータ構造を選ぶことが大切です。