第6回(2011年11月16日)


今日の演習

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


今日の目標


繰り返し文(前回の内容:for 文)

 コンピューターは繰り返し処理が得意です.人間のように飽きてしまうことなく、黙々と処理を繰り返してくれます.

 例えば、画面に Hello! を10回表示したい場合、これまでの知識では次のプログラムとなります.

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

#include <stdio.h>

main()
{
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
}

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

10回程度であれば、これでも良いかも知れませんが、100回表示せよとなるとこれではどうしようもありません(根気が必要です).そこで、繰り返し文が登場します.

for 文

 繰り返し文には for 文while 文があります.まずは for 文を使ったプログラムを見て見ましょう.繰り返し文を使うと、先のプログラムは次のようになります.ファイル名を 1109-1.c として打ち込み、コンパイルし実行してください.

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

#include <stdio.h>

main()
{
    int i;

    for (i = 0; i < 10; i++)
    {
        printf("Hello!\n");
    }
}

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

上のプログラムで、繰り返し文と呼ばれるのは

for (i = 0; i < 10; i++)
{
    printf("Hello!\n");
}

の部分です.このように書くことで { } で囲まれたブロック文が10回繰り返され、先のプログラムと同様の結果が得られます.

 途中 i++ というものがありますが、これは i = i + 1 と同様であると思ってください.i = i + 1 と書く場合、= が代入をあらわすことを思い出せば、左辺の i に i + 1 の結果を代入すると読め納得できます.(等号だと勘違いすると変なことになります.)

 また次のように変えると、1〜10までの整数を表示するプログラムになります.

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

#include <stdio.h>

main()
{
    int i;

    for (i = 0; i < 10; i++)
    {
        printf("%d\n", i+1);
    }
}

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

 for 文の括弧の中にはセミコロン ; で区切られた3つの式があります.通常、for 文の中にあらわれる変数は整数型です(実数型の場合もあります).

  • はじめの式は i = 0 となっています.ここで通常初期値設定を行います.つまり、i の初期値を 1 と設定しています
  • 2つめの式は、先の条件分岐のところで現れた条件式で、この場合 i < 10 が真である間ブロック文を繰り返せということを示しています
  • 3つめの式は繰り返しの度に実行される式で i++ によって i が毎回1ずつ増えます

 結果、この for (i = 0; i < 10; i++) は

「はじめに i を 0 とし、i が 10 より小さい間ブロック文を繰り返し、繰り返しの度に i を1 ずつふやせ.」

と読むことができます.

 例えば、2〜100までの間の偶数を表示するには次のようなプログラムになります.

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

#include <stdio.h>

main()
{
    int i;

    for (i = 2; i <= 100; i = i + 2)
    {
        printf("%d\n", i);
    }
}

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

ここでは、初期値を i = 2 とし、毎回の i の増やし方は i = i + 2 と2つずつ増やしています.また、処理は i <= 100 が満たされている間繰り返されますから、2〜100までの間の偶数が表示されます.


 次のサンプルプログラムは1〜5までの和と積を計算し表示します.ファイル名を 1109-2.c として打ち込み実行してください.

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

#include <stdio.h>

main()
{
    /* 和、積を表す変数 wa, seki 等を宣言 */
    int i, wa, seki;

    /* 和、積を表す変数 wa, seki を初期化 */
    wa = 0;
    seki = 1;

    /* wa, seki を i = 1〜5まで計算を繰り返し求める */
    for (i = 0; i <5; i++)
    {
    /*(右辺)の計算結果を(左辺)に代入し、wa, seki の値を更新 */
        wa = wa + (i+1);
        seki = seki * (i+1);
    }

    printf("和=%d\n", wa);
    printf("積=%d\n", seki);
}

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

このプログラムは大変短く簡単ですが、実はこのプログラムは数値計算プログラムの基本形と呼べるものです.ながれは、

  1. 利用する変数の初期化を行い
  2. 繰り返し文をもちいて
  3. 何らかの計算を繰り返し
  4. 結果を表示する

となっています.このプログラムをよく見て、これまでの内容を疑問なく理解できているか確認してください.確認:「 = 」 は「等しい」ではなく、「右辺の値を左辺の値に代入」という意味です。ですので wa, seki の計算部分はこのように書けます。(古い(右辺の) wa, seki から、新しい(左辺の) wa, seki に更新していく.)よく分からない人は必ず質問すること.

 変数は利用する前に必ず初期化(適切な値の代入)を行って下さい.変数は用意した直後の内容は不定です.つまり、なんらかの値を代入する前にその変数の保持している値が 0 である保証はありません.例えば、先の和と積を求めるプログラムで wa =0, seki = 1 を忘れると思ってもいない結果になる可能性があります.i に関しては for 文の中でまず i = 0 と初期化されるのでこの場合問題ありません.


(復習)応用課題1

 自然数 n を入力すると 1〜n の間の3又は7の倍数をすべて表示するプログラムを作成せよ.(for 文と if 文を利用.)

 (行き詰まったら サンプル を参考にしてください. このようなfor 文と if 文の組み合わせが、今後作るいろいろなプログラムの基本的な構造になります。)

(復習)応用課題2

 自然数 n を入力すると、n が素数なら 1, 素数でないなら 0 を表示するプログラム(素数判定プログラム)を作成せよ.

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


(今日はここから)

while 文

 while 文は次のように使われます.

while (条件)
{
    ブロック文
}

条件部分に書かれた条件式が真である間ブロック文が繰り返し実行されます.先の for 文を使った例も while 文を使って書き換えることができて、

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

#include <stdio.h>

main()
{
    int i;

    for (i = 0; i < 10; i++)
    {
        printf("Hello!\n");
    }
}

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

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

#include <stdio.h>

main()
{
    int i;

    i = 0;
    while (i < 10)
    {
        printf("Hello!\n");
        i = i+1;
    }
}

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

と同等です.

 このように、for 文と while 文は実質的に全く同じものです.プログラムが見やすくなる方を選んで使えばよいでしょう.上記2つの例では先の for 文を用いたプログラムの方が意味を理解しやすいかと思います.


 例えば、次のような例では while 文が適しています.1116-1.c として打ち込んで実行してみてください.

 このプログラムはキーボードから整数値を入力していき、その数字を加算します.入力された数値が0であれば繰り返し処理を終了して合計値を表示するものです.

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

#include <stdio.h>

main()
{
   /* 変数の型の宣言 */
    int n, sum;

   /* 変数の初期化 */
    n = -1;
    sum = 0;

    /* n が 0 でなければ、以下の処理を繰り返す n が 0 ならば以下の処理をやめる */
    while (n != 0)
    {
       /* 変数入力 */
        printf("整数を入力してください ");
        scanf("%d", &n);
       /* 入力された数を足す */
        sum = sum + n;
    }

    /* 結果表示 */
    printf("合計=%d\n", sum);
}

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

 はじめに n = 0 とせずに n = -1 としているのは n = 0 としてしまうと、 while (n != 0) の条件式がはじめから偽となってしまうからです.この場合 -1 という数値にはあまり意味がありません.0 でなければよいのです.

 もちろん同様の動作をするプログラムを for 文を用いて作成することも可能です.


課題1

 (復習)応用課題1で作成したプログラムと同様のものを、while文を使って作成せよ.


多重繰り返し文(多重ループ)

 for 文、while 文は入れ子にすることができます.例えば次のように for 文の中にさらに for 文があるような繰り返し文を、2重ループと呼びます.もちろん、3重、4重ループも作ることができます.次のプログラムを 1116-2.c として打ち込み実行してください.ただし、実行する前にどのような出力が出るか予想してから実行してください.予想通りであれば、繰り返し文の理解は十分できているといえるでしょう.

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

#include <stdio.h>

main()
{
    int i, j;

    for (i = 0; i < 3; i++)
    {
      for (j = 0; j < 5; j++)
      {
           printf("i=%d, j=%d\n", i, j);
      }
    }
}

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

 実行すると分かりますが、多重ループでは、もっとも内側のループ(繰り返し文)が先に実行されます.


課題2

 整数 i, j, が 0 < i < 50, 0 < j < 50, を満たすとし、正の整数 n を入力すると、n = i + j を満たす全ての i, j を表示するプログラムを作成せよ. (2重ループと if 文)

課題2'

 整数 i, j, k が 0 < i < 50, 0 < j < 50, 0 < k < 50, を満たすとし、正の整数 n を入力すると、
n = i + j + k を満たす全ての i, j, k を表示するプログラムを作成せよ.

課題2''

正の整数 r1, r2 (r1 > r2) を入力すると、原点を中心とした半径 r1 の球内部に含まれ, かつ原点を中心とした半径 r2 の球内部に含まれない, 正の整数座標(x, y, z)を全て表示するプログラムを作成せよ.

課題3

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


扱える数値の大きさ

 コンピューターは無限に大きな数値を扱うことはできません.以下に変数が扱えるおおよその範囲を示しておきます.こういった話は実は機種に依存するので、注意が必要.)

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

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


定積分の近似値

積分が和の極限だということを使うと,計算機で定積分の近似値を簡単に計算できます.

以下は定積分

の近似値を求めるプログラムです.1116-3.cとして打ち込み実行してください.プログラムの概要は以下の通り。

1. まず積分区間(0 〜 a)を、 n 個の、幅 d = a/n の領域に分割。
2. i 番目の領域の中心(x = (i+0.5)*d)での関数の値(y = 1 - x*x)を高さとする長方形の面積が = y*d と得られるので、それらを全区間に渡って足し合わせる。(紙に絵を描いてみるとすぐ分かります。)

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

#include <stdio.h>

main()
{
    /* 実数型変数の宣言 */
     float f, x, y, a, d;

    /* 整数型変数の宣言 */
     int i, n;

    /* 積分範囲 を代入 */
    a = 1.0 ;

    /* 分割数 n を代入 */
    n = 100 ;

    /* 分割の幅 d を計算. 整数型変数 n を,ここでだけ実数型として扱って計算(下の注を参考)*/
    d = a / (float)(n) ;

    /* fの初期化 */
    f = 0.0 ;

    /* 積分を計算する繰り返し文 */
    for (i = 0; i < n; i++)
    {
       /* 整数型変数 i を, ここでだけ実数型として扱って計算(下の注を参考) */
       x = ((float)(i)+0.5) * d;
       y = 1.0 - x * x;
       f = f + y * d;
    }

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

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

分割数 n を大きくすると(例えば 10 -> 100 -> 1000 としていくと),2/3=0.66666・・・に近づくことを確認してください.

  注:プログラムの途中で、一時的に変数の型を変更すると便利な事があります.(上の例での n, i 等.)このような場合「(一時的に使用したい変数の型)(変数)」とすることで, 一時的にその文でのみ指定した型の変数として扱う事ができます. つまり, 例えばプログラム始めで float a; と宣言されていても, ある文中で (int)(a) 書かれていれば,その文中のみでは a は int 型変数として扱われます.(その文以外のところでは、始めに宣言された型で扱われます.)(int)(a), (float)(n) 等, 整数型, 実数型どちらでも使用可です. (例えば a = 2.9 等の場合 (int)(a) は 2 となります. 実数型変数を整数型にした場合, 小数点以下は 0 になります.)


課題4

 例えば積分区間を -2 〜 3 とした場合の定積分の近似値を計算求めよ.また適当な関数, 積分区間でいろいろ計算してみてください.

課題5

多重繰り返し文を使って,z=1-(x2+y2)とz=0平面とで 囲まれる領域の体積の近似値を求めよ.


プログラムの停止の仕方とファイルの消し方(前回の説明)

 プログラムは正しく動作し、正しく停止することが重要ですが、停止しないプログラムを書くのは大変簡単です.停止しないプログラムはたいていの場合、プログラミングミスが原因です.例えば、次のプログラムは停止しません.1109-4.c として打ち込み実行してみてください.

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

#include <stdio.h>

main()
{
    int i;

    for (i = 1; i >= 1; i++)
    {
        printf("Hello!\n");
    }
}

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

条件式 i >= 1 が真でありつづけるため停止しないわけです.(後の述べる扱える数値の大きさを超えるとおかしなことになるので、そこで停止する可能性はありますが・・.)

 今後、色々なプログラムを作ってもらいますが、何らかのプログラミングミスで停止しないプログラムになっていて、それを実行してしまった場合は、

Ctrl + c  (Ctrl キーを押しながら c のキーを押す)

によって強制的に終了させることができます.覚えておいてください.

 また、エラーのあるプログラムによっては core というファイル名のファイルを作成してしまう場合があります.このファイルは、当面不要なので、消してしまいましょう(ファイルサイズが大きいので).以前、0 での割り算を行うプログラムを実行した人は、多分この core ファイルができているはずです.


今日学んだ事

  • 繰り返し文を使えるようになりました
  • より複雑なプログラムを理解し、つくることができるようになりました

戻る