プログラミング入門(金曜1・2限)講義資料(2008年後期)

プログラミング入門 第4回

前回の復習

2重ループ

以下のような九九の表を表示するというプログラムを考えてみます.

1の段: 1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
2の段: 2*1=2 2*2=4 2*3=6 2*4=8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
...
9の段: 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81

まず,大きく考えて1の段〜9の段を表示したいのですから,これはwhile 文を使ってiの段を表示するように書けそうです.

// 1の段〜9の段を表示するための繰り返し
int i;
while (i <= 9) {
    // ここで i の段を表示する
    i++;
}

一方,iの段の表示(横方向の表示)も while文を使って書けそうですね.

// 1の段〜9の段を表示するための繰り返し
int i = 1;
while (i <= 9) {
    // i の段を表示するための繰り返し
    int j = 1;
    while (j <= 9) {
        // i * j を表示する
        j++;
    }
    i++;
}

このように繰り返しの中に繰り返しがある構造を,2重ループと言います.2つのwhile文で,別々の変数を使って繰り返しの数を数える必要があることに注意してください.

2重ループの中で break 文を使うと,一番内側のwhile文から脱出します.

演習(九九)

上の九九のプログラム Kuku を完成させなさい.

演習(放物線)

余裕のある人向け

領域 y >= x * x ( -2 <= x <= 2, 0 <= y <= 2 ) を次のように表示するプログラム Parabola を作成してください.

......*****************************.....
.......***************************......
.......***************************......
.......***************************......
........*************************.......
........*************************.......
.........***********************........
.........***********************........
..........*********************.........
..........*********************.........
..........********************..........
...........*******************..........
............*****************...........
............*****************...........
.............***************............
.............***************............
..............*************.............
...............***********..............
................*********...............
.................*******................

繰り返し(for文)

次のような構造は,実際のプログラムで頻繁に現れます.

  i = 0;
  while (i < 10) {
    処理;
    i++;
  }

実は,このような構造はもう少し簡単に書けるようになっています.上のプログラムは,for文を使って次のように書くことができます.

  for (i = 0 ; i < 10 ; i++) {
    処理;
  }

これらは全く同じ動作をします.では,for文なんか要らないのではと思うかも知れませんが,while文ではちょっとした欠点があります.

これに対して,for 文は for 文のところだけをみて繰り返しの構造を把握することができるという点で優れています.

while文,for文どちらを使っても間違いではありません.わかりやすい方で書いてください.

for 文の中でも break 文を使うことができます.break すると,for 文から脱出することができます.

変数の有効範囲

変数は,例えば int a; のように書くと作り出すことができます.では,その変数はいつなくなるのでしょうか?

Javaのプログラムは,{}のペアで囲まれたブロックでできています.あるブロック内で作られた変数は,そのブロックの中だけで有効です.あるブロックを出ると,その中で作られた変数は消滅し,それ以降使うことは出来ません.

{
    int i;

    // ここでは i が使える
    while (...) {
        int j;
	// ここでは i と j が使える
        if (...) {
            int k;
            // ここでは i, j, k が使える
        }
	// ここでは i と j が使える
    }
    // ここでは i が使える
}

ただし,for 文で以下のようにして作成した変数は,for 文の中だけで有効です.

for (int i = 0 ; i < 10 ; i++) {
	// i はこのブロックの中だけで有効
}
// この時点で変数 i は消滅している

配列

これまでの知識で,2つの数の和を求めたり,3つの数の最大値を求めたりするプログラムは作ることができるでしょう.では,ここで100個の数の和を求めよと言われたらどうしますか? 延々と長いプログラムを書かないといけないのでしょうか?

でも,扱うデータの数が大きくなるに従って,プログラムもたくさん書かないといけないのでは,コンピュータを使っている意味がありませんね.

そこで登場するのが配列です.数学では名前が違うたくさんの変数を使う代わりに x1, x2, x3のように,変数に添字をつけて使っています.Java でも同じようなことができます.

例えば,5つの要素を持つint型の配列は,こんなイメージです.

この配列を作るには,こんな風に書きます.

    int[] x = new int[5];

これは,x[0] 〜 x[4] という5個のint型の変数を作り出すことに相当します.

同じように,50個の要素を持つ double 型の配列 y は次のようにして作ります.

    double[] y = new double[50];

配列のそれぞれの要素は普通の変数と同じです.例えば x[0] =Keyboard.intValue(); や x[1]++;,x[1] = x[0] + 100; のように書くことができます.

int型,long型,double型等の配列を作ると,最初はそれぞれの要素には 0 (0.0) が入っています.

さて,沢山の箱を作ることができても,例えばその中身を全部 10 にしたいという場合に,いちいち x[0] = 10; x[1] = 10; x[2] =10; のように延々と書かないといけないならやっぱり大変です.でも,そんな心配は要りません.配列の添字には変数を使うことができます.これが配列の利点です.

なお,添字は整数型(int型)である必要があります.

    // x[0] 〜 x[99] の全てを 10 に設定する.
    int[] x = new int[100];
    for (int i = 0; i < 100 ; i++) {
        x[i] = 10;
    }

Javaの配列は,自分が幾つの要素を持っているかを知っているので,こう書くこともできます.x.length というのは,配列 x の要素の数(ここでは100)という意味になります.

    // x[0] 〜 x[99] の全てを 10 に設定する.
    int[] x = new int[100];
    for (int i = 0; i < x.length ; i++) {
        x[i] = 10;
    }

初期値の代入

配列に何らかの値を入れておきたいことがあります.このとき次のように書くのは大変です.

  // JR阪和線の駅間距離の配列
  double[] dist = new double[4];
  dist[0] = 1.5; // 天王寺〜美章園
  dist[1] = 1.5; // 美章園〜南田辺
  dist[2] = 0.9; // 南田辺〜鶴ヶ丘
  dist[3] = 0.8; // 鶴ヶ丘〜長居

この代わりに,次のように書くことができます.

  // JR阪和線の駅間距離の配列
  double[] dist = {1.5, 1.5, 0.9, 0.8};
  // 自動的に配列 dist の大きさは4になる.

例外

よくある間違いとして,「配列の大きさより大きい添字を指定してしまう」というものがあります.


このファイルをダウンロード ■ UNIX用(EUC版) ■ Windows用(SJIS版)
(上のどちらかのリンクを右ボタンでクリックして「リンク先を名前をつけて保存」して下さい)

public class OutOfBounds {
    public static void main(String[] args) {
	int[] x = new int[100];
	// x[99]までしか許されていないのだが…
	x[1000] = 1;
    }
}


このようなプログラムを実行すると,実行時にエラーが検出され,例外が発生します.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1000
        at OutOfBounds.main(OutOfBounds.java:5)

java.lang.ArrayIndexOutOfBoundsExceptionというのは,配列の添字が許されている範囲を越えているということを表す例外です.また,エラーはプログラムの4行目にあるということ,添字の値は1000だったということも分かります.

演習

5個の実数をキーボードから入力し,配列に覚えた後,最後に配列の中身を表示するプログラム ArrayExercise を書いて下さい.

1: 10
2: 5.5
3: 20.5
4: 8
5: 9
10.0 5.5 20.5 8.0 9.0

ヒント: やりたいことは以下のようなこと.繰り返しが使えるところは for文(またはwhile文)にする.

・配列 x を作る double[] x = new double[5];
・1: と表示
・x[0] にキーボードから入力
・2: と表示
・x[1] にキーボードから入力
・....
・配列の中身を表示する.

それができたら,最後に表示するときに,入力した順番と逆順に表示するように変更して下さい.

1: 10
2: 5.5
3: 20.5
4: 8
5: 9
9.0 8.0 20.5 5.5 10.0

さらに,全部の合計と平均を求めてください.

1: 10
2: 5.5
3: 20.5
4: 8
5: 9
9.0 8.0 20.5 5.5 10.0
Total: 53.0
Average: 10.6

余裕がある人は,さらに入力された値が 0 ならば,入力をそこで終了するようにしてください.いくつ入力されるかわからないので,平均を求めるときに単純に5で割ってはいけません(入力された個数で割る→つまり入力された個数を数えておく必要がある).

1: 10
2: 5.5
3: 20.5
4: 0
20.5 5.5 10
Total: 36.0
Average: 12.0	(この場合,平均を求めるときに3で割ることに注意)

課題4-1 (最大値と最小値)

一連の整数(1〜100まで)を5つ入力し,その中の最大値と最小値を表示するプログラム MinAndMax を作ってください.

余裕がある人バージョン: 0 を入力することで入力の終りとします.10個までは入力できるようにして下さい.

Number: 10
Number: 40
Number: 90
Number: 80
Number: 40
最大: 90
最小: 10

ヒント: 最小値・最大値を探す方法が難しいと思います.人間がやるときはどうやっているかを細部まで考えましょう.

ヒント: 最小値の場合: 「最初の値と次の値を比較する.小さい方を覚える.その値とその次の値を比較する.小さい方を覚える.その値とその次の値を比較する.小さい方を覚える…」

ヒント: まずは最小値だけを表示するプログラムを考えて,うまく動いたら最大値も表示するように拡張しましょう.

課題4-2 (ヒストグラム)

学生の成績の分布をヒストグラムとして表示するプログラム Hist を作ってください.

0〜100の整数をキーボードから繰り返し読み込み(-1が入力されたら終わり),0点台(0〜9点),10点台(10〜19点),...,90点台, 100点の学生がそれぞれ何人いるかをヒストグラムで表示してください.

点数: 98
点数: 22
点数: 94
点数: 100
点数: 45
点数: 92
点数: 29
点数: -1

0点台: 
10点台: 
20点台: **
30点台: 
40点台: *
50点台: 
60点台: 
70点台: 
80点台: 
90点台: ***
100点: *

x点台の学生の数を覚えるために配列 hist を使います.hist[x] が,x * 10点台の学生の数を格納するようにしてください.つまり,hist[0] は0点台の学生の数,hist[1] は 10点台の学生の数,... とし,100点の学生の数は hist[10] に格納します.つまり,配列には点数を入れておくのではなく,成績の分布を入れることになります.

点数から hist のどこに入れるか(つまり添字の値)を計算する必要があります.

棒グラフ(*)の表示は,"*" を繰り返し表示すれば良いでしょう.

最後の100点は「100点台」と表示しても構いません.

段階的詳細化を忘れないように.プログラムの構造は大体次のようになるでしょう.

1. ソースプログラム,2. 実行結果,3. 苦労したところや改善すべき点,質問,感想 を書くこと.

プログラムリストはインデントを正しくしてから提出すること.(XEmacs を使っている場合は,プログラム全体を範囲指定してから M-x indent-region を使うとよい.(M-x は ESC を押してから x を押す.))