既に学習したように,Cでは任意の長さの配列を作ることはできず, あらかじめ必要十分な大きさの要素を確保しておかな ければならない。
およそ10個から20個の範囲のデータを処理する,ということであれば
あらかじめ余裕を持って100個程度の配列を宣言しておく。このときに,
最大要素数をあとから変更しやすいように #define
の
マクロ定義を利用する。
以下のプログラムは100人以下の得点を読み込んで,その平均点を求める ものである。
#include <stdio.h>
#include <stdlib.h>
#define N_MAX 100 /* 最大100人 */
int main()
{
int n; /* 人数 */
int pt[N_MAX];
char buf[50]; /* 読み込み用バッファ */
int i, sum=0;
n=0; /* 人数を0にリセット */
while (1) { /* 1 は Ruby でいう true で,常に真を表す */
if (n >= N_MAX) {
fputs("もう読めないの,ゴメン…\n", stderr);
break; /* ループを抜ける */
}
fprintf(stderr, "%d人目の点は?(終了は C-d): ", n+1);
if (fgets(buf, sizeof buf, stdin)) {
/* 読み込みがあれば得点を記憶 */
pt[n++] = atoi(buf);
} else {
/* 読み込み終了 */
break;
}
}
/* ここから平均点の計算. n に読んだ人数が残っている */
for (i=0; i<n; i++)
sum += pt[i];
printf("\n%d人の得点の平均は%f点でした\n", n, (float)sum/n);
}
成績処理などのように,性質の同じ数値をたくさん読み込んで,
それらの平均値や標準偏差を計算するようなことはデータの種類にかかわらず
必要になる。そのような処理はどんなプログラムでも利用できるように
関数化しておくと良い。たとえば,平均点を求める関数 average
,
標準偏差を求める関数 stddev
を作っておけば,
:
int 配列[100];
float average(配列), stddev(配列); /* 関数のプロトタイプ宣言 */
float heikin, hensa; /* 平均と標準偏差をしまう変数 */
:
〜配列 に数値を読み込む
:
heikin = average(配列);
hensa = stddev(配列);
:
のようにして手軽に平均値と標準偏差を求めることができる。ほかにも たくさんのデータを元に計算して意味のあるような結果を求めることが 必要になることは多い。
このようなときに,一次元配列を渡す方法にはいくつかあるが,
最も平易に記述できる方法は以下のようになる(average
の例)。
/* もらう側の関数定義: 仮引数に注目 */
float average(int points[], int n)
{
.......
}
/* 呼出側の記述 */
int main()
{
int x[5] = {1, 2, 3, 4, 5};
float avg;
avg = average(x, 5);
}
Rubyの場合は,配列に実際に入っている要素の個数を .length
で調べることができた。たとえば,
# Rubyの場合
x = [1, 2, 3, 4, 5]
print x.length
とやると x.length
は5になる。しかし,C言語では
宣言した配列のどの位置まで実際のデータが入っているかは,プログラムを
作る人が常に管理しておかなければ分からない。したがって,一次元配列を
別の関数に受け渡すときは,
をセットにして別の関数に渡すようにする必要がある。
【変数のアドレスについて復習】
単純変数 var のアドレスを示すには
変数名の前に &
をつける
var → &var
配列変数 arr[*] のアドレスを示すには,
(&
をつけても良いが) 大括弧を一つはぎ取る
arr1[*] → arr1
arr2[*][*] → arr2[]
以上のことから,配列
x[] = {1, 2, 3, 4, 5};
を別の関数に渡すときは,その先頭のアドレスである x
と
要素数である5を渡すようにする。
おさらいで例示した ave100.c
を
改良し,平均点を求める関数を別にすると以下のようになる。
#include <stdio.h>
#include <stdlib.h>
float average(int data[], int n)
{
int sum=0;
int i;
for (i=0; i<n; i++) {
sum += data[i];
}
return (float)sum/n;
}
#define N_MAX 100 /* 最大100人 */
int main()
{
int n; /* 人数 */
int pt[N_MAX];
char buf[50]; /* 読み込み用バッファ */
int i, sum=0;
n=0; /* 人数を0にリセット */
while (1) { /* 1 は Ruby でいう true で,常に真を表す */
if (n >= N_MAX) {
fputs("もう読めないの,ゴメン…\n", stderr);
break; /* ループを抜ける */
}
fprintf(stderr, "%d人目の点は?(終了は C-d): ", n+1);
if (fgets(buf, sizeof buf, stdin)) {
/* 読み込みがあれば得点を記憶 */
pt[n++] = atoi(buf);
} else {
/* 読み込み終了 */
break;
}
}
/* 平均点の計算は 別関数にやってもらう */
printf("\n%d人の得点の平均は%f点でした\n", n, average(pt, n));
}