3.配列
多くの同じ型のデータをまとめて扱う時、「配列」を用います。科学計算のためのプログラムでは必須です。
3.1 配列要素の参照と代入
配列の個々の要素にアクセスするには、何番目の要素かを[]でくくった添字として指定します。C言語では配列の添字は0から始まることに注意してください。
<例3−1>
#include <stdio.h>
#define ARRAY_SIZE 10
int main(void) {
int
i;
int
data[ARRAY_SIZE]; /* int型の配列dataを宣言 */
/*
dataの各要素に添字と同じ値を代入 */
for
(i = 0; i < ARRAY_SIZE; i++) {
data[i]
= i;
}
/*
dataの各要素の値を表示 */
for
(i = 0; i < ARRAY_SIZE; i++) {
printf("%d\n",
data[i]);
}
return
0;
}
[解説] 配列の宣言と初期化
上の例では、int型の配列dataの各要素に添字と同じ値を代入し、その後先頭から順に表示しています。
【課題3−1】(プログラムを提出)
以下のプログラムは、単に配列の要素を順に表示するものである。これを、配列の各要素の前後を反転した後に先頭から表示するプログラムに書き換える。
(data[0]=0.1, data[1]=1.2, ...,
data[9]=9.0 という配列を、data[0]=9.0, data[1]=8.9, ..., data[9]=0.1 という配列にする)
#include <stdio.h>
#define ARRAY_SIZE 10
int main(void) {
/*
float型の配列dataを宣言し、初期化 */
float
data[ARRAY_SIZE]=
{0.1,
1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0};
int
i;
/*
dataの各要素の値を表示 */
for
(i = 0; i < ARRAY_SIZE; i++) {
printf("%3.1f\n",
data[i]);
}
return
0;
}
[解説] 変数値の入れ替え
《プログラム例》
3.2 配列のアドレス
配列を宣言すると、指定したデータ型の変数のためのメモリが、指定した要素の数だけ連続したアドレスに確保されます。たとえば
double data[4];
と宣言すると、「番号付きの引き出し」の例えを使えば、double型の1つの変数には8つの引き出し(8バイト)が必要ですので、配列dataには8×4で32個の連続した番号の引き出し(連続した32バイトのメモリ)が割り当てられます。
次の例は、配列の各要素のアドレスを表示するものです。配列のアドレスの参照のしかたについては、下の[解説]で必ず確認しておいてください。
<例3−2>
#include <stdio.h>
int main(void) {
double
data[4]; /*
double型の配列dataを宣言 */
int
i;
/*
dataの各要素のアドレスを表示 */
for
(i = 0;i < 4; i++) {
printf
("address of element #%d = %p\n", i, &data[i]);
}
return
0;
}
(実行結果例)
address of element #0 = 0xbffffa80
address of element #1 = 0xbffffa88
address of element #2 = 0xbffffa90
address of element #3 = 0xbffffa98
[解説] 配列のアドレスを参照する
この例ではあえてアドレスの値を表示してますが、実際には、プログラマがある配列に割り当てられたメモリのアドレスの値(引き出しの番号)を直接知る必要はほとんどありません。しかし、アドレスの値をポインタに渡したり(後述)、関数の引数として渡したり、というケースはしばしば出てきます。後者の代表がscanf関数です。
<例3−3>
#include <stdio.h>
int main(void) {
char
str[32]; /*
文字列strを宣言 */
scanf("%s",
str); /* キーボードからstrに文字列を入力*/
printf("%s\n",
str); /* strの中身を表示*/
return
0;
}
[解説] 文字と文字列
上の例では、キーボードからの文字入力をうけるために、scanfで文字列(文字型の配列)strのアドレスを引数として渡しています。scanfにアドレスを渡すのは他のデータ型の場合と同様です。
なお、printf関数には通常は変数の値を引数として渡しますが、「%s」で文字列型に指定した場合は、文字列の先頭アドレスを渡します。
3.3 多次元配列
C言語では、配列の添字を増やすことで多次元配列を使うことができます。1次元配列がベクトルなら、2次元配列は行列ということになります。
<例3−4>
#include <stdio.h>
#define ROWNUM 3
#define COLNUM 2
int main(void) {
int
data[ROWNUM][COLNUM]; /*
int型の2次元配列dataを宣言 */
int
i, j;
/*
dataの各要素の行番号x列番号の値を代入 */
for
(i = 0; i < ROWNUM; i++) {
for
(j =0; j < COLNUM; j++) {
data[i][j]=i+j;
}
}
/*
dataの各要素の値を表示 */
for
(i = 0; i < ROWNUM; i++) {
for
(j = 0; j < COLNUM; j++) {
printf("%d\t",
data[i][j]);
}
printf("\n");
}
return
0;
}
[解説] 2次元配列の宣言と初期化
上の例は、3×2の2次元配列の各要素に、その要素の行番号と列番号の和を代入し、その後まとめて表示するものです。2次元配列の要素をまとめて扱う時には、この例のように2重ループになります。
【課題3−2】(プログラムと実行結果を提出)
<例3−4>を参考にして、九九の表を2次元配列として作成し表示するプログラムを作る。
《プログラム例》
1次元配列と同様、2次元配列についても連続したアドレスのメモリが確保されます。<例3−4>と<例3−5>で用いている3×2の2次元配列dataは、意味としては
data[0][0] data[0][1]
data[1][0] data[1][1]
data[2][0] data[2][1]
という行列データですが、メモリの中では
data[0][0]
data[0][1]
data[1][0]
data[1][1]
data[2][0]
data[2][1]
というように、一列に並んでいます。下の例はその実際の様子を示すものです。
<例3−5>
#include <stdio.h>
int main(void) {
int
data[3][2]; /*
int型の2次元配列dataを宣言 */
int
i, j;
/*
dataの各要素のアドレスを表示 */
for
(i=0; i<3; i++) {
for
(j=0; j<2; j++) {
printf("address
of data[%d][%d] : %p\n", i, j, &data[i][j]);
}
}
return
0;
}
(実行結果の例)
address of data[0][0] : 0xbffffa80
address of data[0][1] : 0xbffffa84
address of data[1][0] : 0xbffffa88
address of data[1][1] : 0xbffffa8c
address of data[2][0] : 0xbffffa90
address of data[2][1] : 0xbffffa94
2次元配列のアドレスの参照のしかたについては、<例3−2>の[解説]をみてください。