第7回(2011年11月30日)


今日の演習

以下の内容で演習を行います.


今日の目標

配列を理解する.

繰り返し文や配列変数のメリットを利用する.


前回の応用課題2, 課題2のサンプルプログラムを載せておきます。後で各自作ったものと比較しながら復習してください.(今日は先に進みます.)

前回の応用課題2

 正の整数を1つ入力すると、その数が素数であれば 0 ( or 「素数です」 )、素数でない場合には1 ( or 「素数ではありません」 )を画面に表示するプログラム(素数判定プログラム)を作成せよ.サンプルプログラム

ヒント: いろいろな方法があると思うが、単純な方法としては、n > 2 の整数が素数である場合には、2 <= i <= n-1 の範囲内のすべての整数 i で n を割ったときの剰余(n%i)がすべて 0 以外となる.ひとつでも剰余が 0 となるのであれば n は素数ではない.

前回の課題3

(2以上の)整数 n を入力すると、n 以下の全ての素数を表示するプログラムを作成せよ.(先の素数判定プログラムを利用. 繰り返し.)サンプルプログラム


扱える数値の大きさ(先週触れました.)

 コンピューターは無限に大きな数値を扱うことはできません.例えば、整数 n を入力すると 1〜n までの積(階乗)を計算するプログラム(前回紹介しました)では、意外と小さな n でおかしな結果となってしまいます. n = 12 まで大丈夫ですが n = 13 でおかしくなります.

変数の型によって、扱える数値の大きさが異なります.以下に各型の扱える数値の範囲を示します.

データ型(変数型) 表現 範囲
char 文字型 -128〜127
int  整数型 -2147483648〜2147483647
long 倍長整数型 -2147483648〜2147483647
float 単精度実数型 およそ 10e-38〜10e38 (有効桁7桁)
double 倍精度実数型 およそ 10e-308〜10e308 (有効桁15桁)

ここで、10eN は 10Nをあらわすとします.整数型は以外と小さな数値までしか扱えないことがわかります(20億程度).それでは困るので、最近のコンピューターはより大きな整数値を扱えるようになってきています.(整数計算をする部分を自分でプログラミングすれば、いくらでも大きな整数を扱えるようになります.例えば Mathematica などはより巨大な整数値を扱えます.もちろん、それにも限界はありますが・・.)


(今日はここから)

配列変数の宣言と利用

C言語に限らず、ほとんどのプログラミング言語には配列変数と呼ばれるものがあります.配列変数は例えば次のように宣言することで用意することができます.

int a[5];

これにより、次のように整数型の変数が5個用意されることになります.

a[0], a[1], a[2], a[3], a[4]

かぎ括弧 [ ] で囲まれた数字は添字と呼ばれます. (ベクトルの成分等を Xi と書きますが、その添字と同じと思ってよいです。) このように添字は 0 から始まるので注意が必要です.次のサンプルプログラムを 1130-1.c として打ち込んで実行してみてください.このプログラムは5個の整数を入力すると、入力値を逆の順番で表示するプログラムです.
- - - - - - - - - - - - - - - -

#include <stdio.h>

main()
{
    /* 整数型変数の宣言 */
     int i, n, c[5];

    /* c[0] 〜 c[4] の入力 */
    for (i = 0; i < 5; i++)
    {
         printf("整数を入力してください:c[%d]= ", i);
         scanf("%d", &c[i]);
    }

    /* c[4] 〜 c[0] の出力 */
    for (i = 0; i < 5; i++)
    {

       printf("c[%d]=%d\n", 4-i,c[4-i]);
    }
}
- - - - - - - - - - - - - - - -

整数型の配列以外にも実数型の配列も作ることができます.

ただし、配列変数の添字には整数型の変数を使います.

float u[6];

と宣言することにより、

u[0], u[1], u[2], u[3], u[4], u[5]

と、5つの実数型変数を作ることができます.


ベクトルの計算(内積の計算)

例えば配列変数 u[i] をベクトル u の i 成分と見なすと、いくつかベクトルの計算が簡単にできることが分かります。以下は二つの3次元ベクトル u, v の内積を求めるプログラム (1130-2.c) です。

- - - - - - - - - - - - - - - -

#include <stdio.h>

main()
{
    /* 変数の宣言 */
     int i;
    /*(ベクトルの各成分は配列で宣言)*/
     float u[3], v[3], naiseki;

    /* ベクトルの各成分 u[0] 〜 u[2] の入力 */
    for (i = 0; i < 3; i++)
    {
         printf("ベクトル u の第%d成分を入力してください: ", i);
         scanf("%f", &u[i]);
    }

    /* ベクトルの各成分 v[0] 〜 v[2] の入力 */
    for (i = 0; i < 3; i++)
    {
         printf("ベクトル v の第%d成分を入力してください: ", i);
         scanf("%f", &v[i]);
    }

    /* 内積の初期化 */
    naiseki = 0.0;

    /* 内積の計算 */
    for (i = 0; i < 3; i++)
    {
        naiseki = naiseki + u[i]*v[i];
    }

   printf("内積=%f\n", naiseki);
}
- - - - - - - - - - - - - - - -


課題1

1130-2.c を、2つの5次元ベクトルの内積を求めるプログラムに改造せよ.


複数の入力値の最大値(最小値)を求める

例えば,実数10個を入力してその最大値を求めるには以下のようにします (1130-3.c) .最大値を求めるときには,一つ変数を別に準備してそれと比べるようにすると簡単です.

- - - - - - - - - - - - - - - -

#include <stdio.h>

main()
{
    /* 整数型変数の宣言 */
     int i;
     float max, c[10];

    /* 実数型配列に値を入力する繰り返し文 */
    for (i = 0; i < 10; i++)
    {
       printf("実数を10個入力してください.(%d つ目) : ", i+1);
       scanf("%f", &c[i]);
    }

    /* max の初期化 */
    max = c[0];

    /* 大小を比べる繰り返し文 */
    for (i = 1; i < 10; i++)
    {
       if (max < c[i])
       {
           max = c[i];
       }
    }

    /* 結果を表示 */
    printf(" max = %f \n", max);
}

- - - - - - - - - - - - - - - -

課題2

1130-3.c を、最大値と最小値と平均値を表示するように改造せよ.

課題3

10 個の実数 R[0] 〜 R[9] を入力すると, その内の最大値と2番目に大きい値を表示するプログラムを作成せよ.

(ヒント:まず最も大きな値 max を求め, そのあとで max > Ri となる最も大きい Ri を求めて表示.)

課題4

6個の実数 A[0] 〜 A[5] を入力すると、まずそれらの平均値 heikin を表示し, 次に V[i] = (A[i] - heikin)2 を i = 0 〜 5 に対し全て表示し, 最後に V[0] 〜 V[5] の平均値(つまり A[i] の分散)を表示するプログラムを作成せよ.


多次元配列変数

多次元配列というものもあります. 多次元配列を用意するには要素を次元数だけ並べて宣言するだけです.

例えば,

int a[2][3];

などのように書くと整数型の a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[1][2] の6個が用意されます.

1次元配列と同様に, float f[2][3][4]; とすれば実数型の配列が宣言され, いずれの場合も配列変数の添字には整数型の変数が使えます.

これを使うと行列のかけ算などが簡単にできます. 以下のプログラムは

の行列Cの要素を計算するプログラムです (1130-4.c) .打ち込んで実行してください.

- - - - - - - - - - - - - - - -

#include <stdio.h>

main()
{
    /* 整数型変数の宣言 */
     int i, j, a[2][3], b[3], c[2];

    /* 整数型配列 a に値を入力 */
    a[0][0] = 3;
    a[1][0] = 4;
    a[0][1] = 2;
    a[1][1] = 1;
    a[0][2] = 5;
    a[1][2] = 9;

    /* 整数型配列 b に値を入力 */
    b[0] = 7;
    b[1] = 8;
    b[2] = 2;

    /* 整数型配列 c の初期化 */
    for (i = 0; i < 2; i++)
    {
       c[i] = 0;
    }

    /* 各成分を計算する繰り返し文 */
    for (i = 0; i < 2; i++)
    {
       for (j = 0; j < 3; j++)
       {
          c[i] = c[i] + a[i][j] * b[j];
       }
    }

    /* 結果を表示する繰り返し文 */
    for (i = 0; i < 2; i++)
    {
       printf(" %d行目の成分 = %d \n", i+1, c[i]);
    }
}

- - - - - - - - - - - - - - - -

課題5

(1130-4.c 等を参考に) 2 行 2 列, 3 行 3 列, 5 行 5 列, (n 行 n 列) の行列同士のかけ算のプログラムを作成せよ.


数値の入力回数をカウントする

次のサンプルプログラムは、 1 〜 9 いずれかの自然数を打ち込むと、それぞれ何回入力されたかを数えるプログラムです (1130-5.c) .0 を入力することで入力を終えることができるようになっています.(途中 if 文の入れ子があります.入れ子構造を分かりやすくするために字下げが行われていることに注意してください.字下げによって、構造がよくわかるはずです.)


サンプルプログラム



課題6

10個の実数 A[0] 〜 A[9] を入力すると、それらを値の大きい順に並べ替えて表示するプログラムを作成せよ. (課題3の応用、発展)


今日学んだ事

  • 多次元配列

戻る