配列

変数を 100 個使いたい時どうする?例えば、100人の受講生の試験の平均を求めたい時。 C言語は変数を使う前に宣言する必要がある。

int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9
    x10, x11, x12, x13, x14, x15, x16, x17, x18, x19,
    x2O, x21, x22, x23, x24, x25, x26, x27, x28, x29,
    x30, x31, x32, x33, x34, x35, x36, x37, x38, x39,
    x40, x41, x42, x43, x44, x45, x46, x47, x48, x49,
    x50, x51, x52, x55, x54, x55, x56, x57, x58, x59,
    x60, x61, x62, x66, x64, x65, x66, x67, x68, x39,
    x70, x71, x72, x77, x74, x75, x76, x77, x78, x79,
    x80, x81, x82, x88, x84, x85, x86, x87, x88, x89,
    x90, x91, x92, x99, x94, x95, x96, x97, x98, x99;

これ、ムリ。エラーなくタイプ完了するのは神業。 一箇所、間違ってます(実は2箇所。わかるかな? え?3箇所あるって?)

その代わり、こうすれば、100 個変数を宣言したことになる。

int x[100];

一つひとつの変数は、x[0], x[1], ... x[99] のように参照する。 x[n] のような変数を 配列 と呼ぶ。

受講生はすでに配列とよく似た概念と記法には出会っている。 数学の教科書見てみよう。添え字のついた変数があるだろ。それ。

xn

配列は難しくない。 ふつうの変数だと x で参照できるところ、x[n] のように参照するってだけ。

添字の範囲に注意

C言語の配列が数学や物理学の添え字付き変数 xn と違う点は、

  • 添字は 0 から始まる。

  • 添字は宣言時の範囲内のみ。

  • 配列要素の型は宣言したものに限る。

例:

int x[100];

x[0] から x[99] までの変数が使える。x[100] の 100 は 100 個 の意味。最初が 0 なので最後は 99 だ。

x[-1]、x[100] は参照できない。エラー。

x[44] = 3.14 としても、x[44]に代入されるのは整数 3。

配列の初期化

基本は、宣言の直後にループで回る。

int x[100];
int i;

for (i=0; i<100; i++) {
    x[i] = 0;
}

宣言時に初期化を楽に済ます方法もある。

int x[100] = {}; // 上のループを使う方法と同じこと!

0 以外で初期化する場合は、地道にループで回るが筋だが、次のような手抜きがある。

int x[10] = {1,2,3};

x は長さ 10 の配列で、先頭から3要素が初期化される。 つまり、x[0]=1, x[1]=2, x[2]=3。その後ろ、x[3]からx[9] は 0 が代入される。

int x[] = {11,22,33};

x は {1,2,3} を代入するにぴったりのサイズ、つまり、長さ 3 の配列として宣言され、 先頭から 3 要素が初期化される。 上の例では x[0] = 11, x[1] = 22, x[2] = 33 となる。

関数の引数にする

  • 配列を引数として受け取る関数(下の例では sum)は、 配列要素の型と仮引数の名前の後ろに [ ] で配列を受け取る。 下の例を見よ。int ary[ ] は int * ary でもよいが、 hkimura は [ ] の方が配列に見えていいと思う。

  • 配列を関数に渡す方は、配列の名前([ ]がつかない)を関数に渡す。

  • 注意 配列を受け取る方は受け取る配列の長さがそのままではわからない。 配列の長さの情報が必要な時は(ほとんどのケースはそう)配列の長さを引数として渡すか、 配列の最後の要素の後ろに配列の要素とならない何らかのマークを入れる。 文字列(文字の配列)は後者。

int sum(int ary[]) { // int を返す関数 sum、引数は int 配列 ary。
  int s = 0;

  s = ary[0] + ary[1] + ary[2];
  return s;
}

int main(void) {
  int m[3] = {10,20,30};

  printf("sum: %i\n", sum(m)); // 関数 sum( )に配列 m を渡す。
  return 0;
}

関数の戻り値に配列

ポインタ、スタックを理解することが必要。

  • 関数の戻り値は *

  • ブロック内で宣言した配列を戻したい時は、配列の宣言に static

#include <stdio.h>
#define N 5
int * add_all(int x[], int value) {
  static int y[N];
  int i;

  for (i=0; i<N; i++) {
    y[i] = x[i] + value;
  }
  return y;
}

int main(void) {
  int x[N] = {1,2,3,4,5};
  int *y;
  int i;

  y = add_all(x, 10);
  for (i=0; i<N; i++) {
    printf("%i, ", y[i]); // 11, 12, 13, 14, 15, がプリントされる。
  }
  printf("\n");
  return 0;
}

上のプログラムは動作はするが、ややいびつ。

例題(1, 2, 3)

次のプログラムわからない時は 成績 B 以上は期待してはダメ。 つまり、良くても C、じゅうぶん D の危険性もあるってこと。

  1. 10個の整数を読んで、5よりも大きい整数が何個含まれるかをプリントする。

  2. 10個の整数を読んで、その最小値をプリントする。

  3. 10個の整数を読んで、その最大値をプリントする。

  4. 10個の整数を読んで、その平均をプリントする。

#include <stdio.h>

void read_a(int xs[], int n) {
  int i;

  for (i=0; i<n; i++) {
    printf("%i? ", i);
    scanf("%i", &xs[i]);
  }
}

int larger_than_5(int x[], int n) {
    int count = 0;
    int i;
    for (i=0; i<n; i++) {
        if (5 < x[i]) {
            // 自分で考えろ。
        }
    }
    return count;
}

int min_a(int x[], int n) {
    int i;
    int min = x[0];

    for (i=1; i<n; i++) {
        //
        //自分で考えろ。
        //
    }
    return min;
}

int max_a(int xs[], int n) {
    //
    //自分で考えろ。
    //
}

float mean(int x[], int n) {
  int sum = 0;
  int i;

  for (i=0; i<n; i++) {
    sum += x[i];
  }
  return /* 自分で考えろ */ ;
}

int main(void) {
  int x[10];

  read_a(x, 10);
  printf("5よりも大きいのは %i 個\n", larger_than_5(x, 10));
  printf("最小: %i\n", min(x, 10));
  printf("最大: %i\n", max(x, 10));
  printf("平均: %f\n", mean(x, 10));
  return 0;
}

関数 も参照のこと。

配列の勉強は 文字列 でするとよい。

index


hkimura.

0.9