1. 配列の概念
配列は、同じ型の要素の集合です。この定義には以下の2つの重要な点があります:
- 配列には1つ以上のデータを格納できますが、要素数は0にはなりません(変数を作成することは本質的にメモリ空間を確保することであり、要素数が0だとコンパイラがどの程度の空間を確保すべきかわかりません)。
- 配列に格納される複数のデータは同じ型である必要があります。
配列は一次元配列と多次元配列に分かれ、特に二次元配列がよく使用されます。
2. 一次元配列の作成
2.1 配列の作成
一次元配列を作成する基本的な構文は以下の通りです:
type array_name[定数];
ここで、typeは配列に格納するデータの型を指定し、array_nameは配列名です。[]の中の定数は配列のサイズを指定します。
int numbers[20];
char letters[8];
double scores[10];
2.2 配列の初期化
配列を作成する際に初期値を与えることもできます。これは初期化と呼ばれます。
// 完全な初期化
int nums[5] = {1, 2, 3, 4, 5};
// 不完全な初期化
int nums2[6] = {1}; // 最初の要素のみ初期化、残りは0で初期化
// エラー: 初期化する値が配列のサイズを超える
int nums3[3] = {1, 2, 3, 4};
2.3 配列の型
配列も型を持ちます。配列名を除いたものが配列の型となります。
int arr1[10]; // 型は int[10]
int arr2[12]; // 型は int[12]
char ch[5]; // 型は char[5]
3. 一次元配列の使用
3.1 配列のインデックス
C言語では、配列のインデックスは0から始まります。n個の要素を持つ配列の場合、最後の要素のインデックスはn-1です。
#include <stdio.h>
int main() {
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
printf("%d\n", arr[7]);
printf("%d\n", arr[3]);
return 0;
}
3.2 配列要素の表示
配列全体の内容を表示するには、forループを使用してすべての要素のインデックスを生成し、それぞれの要素にアクセスします。
#include <stdio.h>
int main() {
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
return 0;
}
3.3 配列への入力
配列に任意のデータを入力することもできます。
#include <stdio.h>
int main() {
int arr[10];
for (int i = 0; i < 10; i++) {
scanf("%d", &arr[i]);
}
for (int i = 0; i < 10; i++) {
printf("%d ", arr[i]);
}
return 0;
}
4. 一次元配列のメモリ上の保存
配列の要素のアドレスを表示することで、配列がメモリ上でどのように保存されているかを確認できます。
#include <stdio.h>
int main() {
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < 10; i++) {
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
結果から、配列の要素はメモリ上で連続して保存されていることがわかります。
5. sizeofを使用した配列要素数の計算
sizeofを使用して配列の要素数を計算できます。
#include <stdio.h>
int main() {
int arr[10] = {0};
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n", sz);
return 0;
}
6. 二次元配列の作成
6.1 二次元配列の概念
一維配列の要素が別の配列であれば、それは二次元配列です。二次元配列の要素がさらに配列であれば、三次元配列となります。
6.2 二次元配列の作成
int matrix[3][5]; // 3行5列の整数配列
double data[2][8]; // 2行8列の浮動小数点数配列
7. 二次元配列の初期化
7.1 不完全な初期化
int arr1[3][5] = {1, 2};
int arr2[3][5] = {0};
7.2 完全な初期化
int arr3[3][5] = {1, 2, 3, 4, 5, 2, 3, 4, 5, 63, 4, 5, 6, 7};
7.3 行ごとの初期化
int arr4[3][5] = {{1, 2}, {3, 4}, {5, 6}};
7.4 列を省略して初期化
int arr5[][5] = {1, 2, 3};
int arr6[][5] = {1, 2, 3, 4, 5, 6, 7};
int arr7[][5] = {{1, 2}, {3, 4}, {5, 6}};
8. 二次元配列の使用
8.1 二次元配列のインデックス
二次元配列のアクセスもインデックスを使用します。行と列を指定することで特定の要素にアクセスできます。
#include <stdio.h>
int main() {
int arr[3][5] = {1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7};
printf("%d\n", arr[2][4]);
return 0;
}
8.2 二次元配列の入出力
二次元配列全体の入出力を行うには、全ての行と列のインデックスを生成します。
#include <stdio.h>
int main() {
int arr[3][5] = {1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
scanf("%d", &arr[i][j]);
}
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
9. 二次元配列のメモリ上の保存
二次元配列の各要素のアドレスを表示することで、メモリ上の保存方法を確認できます。
#include <stdio.h>
int main() {
int arr[3][5] = {0};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
return 0;
}
結果から、二次元配列の各要素もメモリ上で連続して保存されていることがわかります。
10. C99での可変長配列
C99以前のC言語では、配列のサイズは定数や定数式、または初期化時に省略できるものしか指定できませんでした。
int arr1[10];
int arr2[3 + 5];
int arr3[] = {1, 2, 3};
C99では、変数を使用して配列のサイズを指定できるようになりました。
int n = a + b;
int arr[n];
このように、配列のサイズは実行時に決定され、初期化はできません。