2次元配列とは?
2次元配列とは、1つの変数に複数の値を格納するためのデータ構造です。通常の1次元配列が縦方向に並んだものであるとすれば、2次元配列は縦横に並んだ表形式のデータを扱うことができます。
例えば、成績管理システムなどでは、学生ごとに複数科目の点数を管理する必要があります。このような場合に2次元配列を使用することで、各学生ごとに科目別の点数をまとめて管理することが可能です。
C言語では、2次元配列は以下のような書式で宣言されます。
データ型 配列名[行数][列数];
例えば、「int」型で3行4列分(計12個)の2次元配列「scores」を宣言したい場合は以下のように記述します。
int scores[3][4];
これにより、「scores[0][0]」「scores[0][1]」「scores[0][2]」…「scores[2][3]」までの領域が確保されます。
2次元配列の宣言方法
2次元配列は、1つの変数に複数の要素を持たせることができます。
C言語では、以下のように宣言します。
データ型 配列名[行数][列数];
例えば、int型の2次元配列を3行4列で宣言する場合は以下のようになります。
int array[3][4];
このように宣言することで、array[0][0]からarray[2][3]まで12個の要素を持った2次元配列が作成されます。
2次元配列の初期化方法
2次元配列を初期化する方法には、以下の3つがあります。
1. 要素ごとに初期化する方法
要素ごとに値を代入していく方法です。例えば、int型の2次元配列a[3][4]を全て0で初期化する場合は以下のように書きます。
int a[3][4] = {
{0, 0, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
};
このように、各行・各列ごとに中括弧{}で囲んだ値をカンマ区切りで並べることで、要素ごとに初期化することが出来ます。
2. 全体を一括して初期化する方法
全体を一括して同じ値で初期化する場合は、以下のような書き方が可能です。
int a[3][4] = {0};//すべての要素が0で初期化される
また、以下のコードだと最初の要素だけ1で初期化され、残りは自動的にゼロ埋めされます。
int a[3][4] = {1};
このような書き方も可能です。これはa[0][0]
だけ1
で他はすべてゼロ埋めされた状態となります。
3. memset関数を使って一括して初期化する方法
memset関数を使って一括して特定の値(通常はゼロ)で配列全体を埋めることも出来ます。ただし、memset関数ではchar型以外のデータ型では正しく動作しないため注意が必要です。
#include <string.h>
// int型2次元配列a[][] を0クリアしたい場合
memset(a , 0 , sizeof(a));
以上がC言語における2次元配列の初期化方法です。
2次元配列への値の代入方法
2次元配列への値の代入方法は、1次元配列と同様に、インデックスを指定して行います。ただし、2次元配列では、行と列の両方のインデックスを指定する必要があります。
以下は、3×3の2次元配列に値を代入する例です。
int array[3][3];
array[0][0] = 1;
array[0][1] = 2;
array[0][2] = 3;
array[1][0] = 4;
array[1][1] = 5;
array[1][2] = 6;
array[2][0] = 7;
array[2][1] = 8;
array[2][2] = 9;
このように、a[i][j]
のように書くことで i
行目 j
列目にアクセスすることができます。また、ループ文を使って繰り返し処理で値を代入することも可能です。
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
array[i][j] = i * j + j + 1;
}
}
この場合、a[0][0]から[2][2]まで順番に1から9までの数値が代入されます。
2次元配列から値を取り出す方法(要素へのアクセス)
2次元配列から値を取り出す方法について説明します。
2次元配列は、行と列の2つのインデックスで要素を指定することができます。例えば、以下のような2次元配列があった場合、
int ary[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10,11 ,12}
};
この場合、array[0][0]
は1、array[0][1]
は2、array[1][0]
は5とを参照することができます。
また、forループを使って全ての要素にアクセスすることも可能です。以下は全ての要素を表示する例です。
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 4; j++) {
printf("%2d ", ary[i][j]);
}
printf("\n");
}
1 2 3 4
5 6 7 8
9 10 11 12
上記コードでは外側のループ変数iが行番号(縦方向)、内側のループ変数jが列番号(横方向)に対応しています。それぞれ最大値までループし、各要素を表示しています。
この方法を使えば、「全ての要素から最大値や最小値を求める」「特定条件に合致する要素だけ取り出す」など様々な処理が可能です。
以上がC言語における2次元配列から値を取り出す方法です。
関数内で使用する場合の注意点
関数内で2次元配列を使用する場合、以下の点に注意が必要です。
1. 関数の引数として渡す場合
関数の引数として2次元配列を渡す場合は、そのサイズも一緒に指定する必要があります。また、ポインタを使って渡すことも可能です。
例えば、以下のような関数があるとします。
void printArray(int arr[][3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
この関数では、2次元配列 arr
を引数として受け取ります。また、行のサイズ rows
も指定します。このようにサイズを明示的に指定しないとコンパイルエラーが発生します。
2. 関数内で宣言する場合
関数内で2次元配列を宣言する場合は、静的なメモリ割当てや動的なメモリ割当て方法があります。
・静的なメモリ割当て
静的なメモリ割当てでは、グローバル変数やstatic変数として宣言された配列はプログラム開始時から終了まで存在し続けるため、同じ関数を二回以上呼び出して、変数宣言の行に到達しても、一度しか宣言処理は行われません。
#include<stdio.h>
void func() {
static int arr[3][3] = {{1, 2, 3}, {4, 5, 6}, {7,8 ,9}};
// 処理...
}
int main() {
func();
return 0;
}
・動的なメモリ割当て
動的なメモリ割当てではmalloc()等の手法を用いることで任意のタイミング・任意箇所から利用可能です。
#include<stdio.h>
#include<stdlib.h>
void func(int row_size,int col_size) {
int **arr;
// メモリ確保
arr=(int**)malloc(sizeof(int*)*row_size);
for(int i=0;i<row_size;i++){
*(arr+i)=(int*)malloc(sizeof(int)*col_size);
}
// 初期化処理(値代入)
for (int i=0;i<row_size;i++){
for (int j=0;j<col_size;j++){
*(*(arr+i)+j)=i+j;
}
}
// 処理...
// メモリ解放処理(忘れずに!)
for (i=0;i<rowSize;++i){
free(arr[i]);
}
free(arr);
}
int main(){
func(5,10);
return EXIT_SUCCESS;
}
このように動的にメモリを割り当てることで、データ量に合わせて配列サイズを柔軟に変更することが可能です。