一次元配列の受け渡し

配列のおさらい

既に学習したように,Cでは任意の長さの配列を作ることはできず, あらかじめ必要十分な大きさの要素を確保しておかな ければならない。

およそ10個から20個の範囲のデータを処理する,ということであれば あらかじめ余裕を持って100個程度の配列を宣言しておく。このときに, 最大要素数をあとから変更しやすいように #define の マクロ定義を利用する。

以下のプログラムは100人以下の得点を読み込んで,その平均点を求める ものである。

ave100.c

#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言語では 宣言した配列のどの位置まで実際のデータが入っているかは,プログラムを 作る人が常に管理しておかなければ分からない。したがって,一次元配列を 別の関数に受け渡すときは,

をセットにして別の関数に渡すようにする必要がある。

【変数のアドレスについて復習】

以上のことから,配列

x[] = {1, 2, 3, 4, 5};

を別の関数に渡すときは,その先頭のアドレスである x と 要素数である5を渡すようにする。

任意個数の数値の平均値を求める関数

おさらいで例示した ave100.cを 改良し,平均点を求める関数を別にすると以下のようになる。

ave100f.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));
}

目次