情報学部 菅沼ホーム 全体目次 演習解答例 付録 索引

第5章 制御文

  1. 5.1 分岐
    1. 5.1.1 if 文
      1. (プログラム例 5.1 ) 円周と面積の計算
      2. (プログラム例 5.2 ) 坪・m2 間の単位変換
      3. (プログラム例 5.3 ) 3 つのデータの最大値と最小値
      4. (プログラム例 5.4 ) データの比較
    2. 5.1.2 switch 文
      1. (プログラム例 5.5 ) データの比較( switch 文)
  2. 5.2 繰り返し
    1. 5.2.1 繰り返し文
      1. (プログラム例 5.6 ) 平均値の計算
      2. (プログラム例 5.7 ) ファイル入出力
      3. (プログラム例 5.8 ) for 文のネスト
      4. (プログラム例 5.9 ) 入力の繰り返し( do-while )
      5. (プログラム例 5.10 ) 最大値(初期設定)
      6. (プログラム例 5.11 ) for 文,while 文,do while 文の比較
    2. 5.2.2 繰り返しの中断
      1. 5.2.2.1 break 文
        1. (プログラム例 5.12 ) 繰り返しの中断( break )
      2. 5.2.2.2 continue 文
        1. (プログラム例 5.13 ) 繰り返しの中断( continue )
  3. 5.3 変数の有効範囲
    1. (プログラム例 5.14 ) 変数の有効範囲
  4. 演習問題5

5.1 分岐

  以上見てきたプログラムは,すべて最初から順番に実行するタイプのものだけでした.しかし,プログラムによっては,必ずしも上から順に実行するだけでなく,その実行順序を変化させたい場合があります.そのような目的のために使用される文を制御文と言います.本章では,主な制御文について説明します.

5.1.1 if 文

  if 文は,そのときの状況により実行の順序を変化させるための文であり,その一般的形式は以下の通りです.
if (論理式) {
	文1(複数の文も可)
}
else {
	文2(複数の文も可)
}
・・・・・・		
  この文の実行は以下のようにして行われます.まず,論理式が評価され,その結果が真であれば,文1が実行され,次に,「・・・」以降に書かれた文が実行されます.この場合は,文2は実行されないことになります.また,偽である場合は,文1は実行されず,文2が実行された後,真の場合と同様,「・・・」以降に書かれた文が実行されます.なお,if 文において,真に対応する部分(文1)は必ず必要ですが,偽に対応する部分( else 以下)は,必ずしも必要ありません.

  また,次の例のように,文1や文2の中にも if 文を書くことができます( if 文のネストと呼びます).同様に,その内部に書かれた if 文の中にも,さらに,if 文を書くことも可能です.
if (論理式1) {
	・・・・・・
	if (論理式2) {
		・・・・・・
	}
	else {
		・・・・・・
	}
	・・・・・・
}
else {
	・・・・・・
}		
  また,プログラムを読み易くするため,if 文内に含まれる文は,次の例のように,何列か段を下げて(字下げを行って)書くようにして下さい.字下げは,プログラムの詳細を見なくても,その構造がわかるようにするためのものです.if 文の場合,条件が満足された場合どこからどこまでが実行されるのかが,一目でわかるように行います.例えば,下の例の場合,a と b が等しい場合,2 行目から 7 行目が実行され,また,等しくない場合,10 行目と 11 行目が実行されることが一目でわかります.また,13 行目と 14 行目は,if 文に関係なく常に実行されることも明確になります.

01	if (a == b) {
02		max = y;
03		min = z;
04		if (min < 0.0) {
05			min = 0.0;
06			a   = b;
07		}
08	}
09	else {
10		max = s;
11		min = g;
12	}
13	x = 9;
14	y = 10;
		

(プログラム例 5.1 ) 円周と面積の計算  ( A ~ F の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  このプログラムでは,半径を入力した後,その値の妥当性(正の値であること)をチェックし( 18 行目),0 以下の場合は何も行わず終了し,また,正の値の場合は目的の計算を行っています.従って,else に対応する部分がありません.なお,11 行目の PI は,Math クラスに定義されている定数であり,円周率 π を表します.プログラムを使う人と作る人は常に同じであるとは限りません.場合によっては,プログラム作成者が予期しないデータが入力され,とんでもない結果が生じる場合がよく起こります.従って,できるだけ,入力データ値等の妥当性をチェックすることをすすめます.

  変数 enshu,men の有効範囲は,型宣言された位置からブロックの終わり( 22 行目)までです.pi や r のように,13 行目より前の位置で型宣言を行えば,それらの変数の有効範囲は,型宣言された位置からメソッドの終わり( 25 行目)までとなりますので,変数 enshu,men の型宣言をそのような位置で行っても構いません.

(プログラム)
/****************************/
/* 円周と面積の計算         */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

		double pi = 3.141592654, r;

		try {
					// 半径の入力
			System.out.print("円の半径は? ");
			r = Double.parseDouble(in.readLine());
					// 計算と出力
			if (r > 0.0) {
				double enshu = 2.0 * pi * r;
				double men   = pi * r * r;
				System.out.println("円周=" + enshu + "   面積=" + men);
			}
		}
		catch (IOException ignored) {}
	}
}
			

(プログラム例 5.2 ) 坪・m2 間の単位変換  ( A ~ C の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次に,面積に関するデータの単位変換をするプログラムについて考えてみます.つまり,与えられたデータが坪単位なら m2 に,m2 単位なら坪に変換するプログラムです.単にデータを与えただけでは,そのデータが坪単位か m2 単位かがわかりませんので,このプログラムでは変数 sw に値を入力することによって識別しています.変数 sw の値が 0 なら m2 から坪に,1 ( 0 以外)なら坪から m2 に変換します.

(プログラム)
/****************************/
/* 坪と㎡の間の単位変換     */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		double x, y;
		int sw;
		try {
					// データの入力
			System.out.print("変換方向(0:坪→㎡,1:㎡→坪)は? ");
			sw = Integer.parseInt(in.readLine());
			System.out.print("変換するデータは? ");
			x = Double.parseDouble(in.readLine());
					// 変換と出力
			if (sw == 0) {           // 坪から㎡
				y = 3.3 * x;
				System.out.println("   xは " + y);
			}
			else {                   // ㎡から坪
				y = x / 3.3;
				System.out.println("   xは " + y);
			}
		}
		catch (IOException ignored) {}
	}
}
			

(プログラム例 5.3 ) 3 つのデータの最大値と最小値  ( A ~ J ,及び,K ~ N の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次のプログラムでは,与えられた 3 つのデータの最大値と最小値を出力しています.この例により,if 文のネスト構造,及び,段落の付け方を理解して下さい.

  また,このプログラムの 27 ~ 30 行目等に示すように,if の後や else の後に続く文が 1 文だけである場合は,それらを囲む「{」と「}」は必要ありません(もちろん,付けても構いません).ただし,次のプログラム
if (式1) {
	if (式2)
		文1;
}
else
	文2;		
に対して,{ } を省略して,
if (式1)
	if (式2)
		文1;
else
	文2;		
と書くと
if (式1)
	if (式2)
		文1;
	else
		文2;		
と解釈されてしまいますので気をつけて下さい.なぜなら,コンパイラが,else に対する if は,else に最も近い if と判断するからです.このような紛らわしさを除くためには,多少余分であっても,{ } を付加した方が良いかもしれません.

  また,この最大値と最小値の問題を
if (a > b && c > a) {
	amax = c;
	amin = b;
}
if (a > b && c < b) {
	amax = a;
	amin = c;
}
・・・・・		
のように,else 文を使用しないで書く人がいますが,余分な比較演算を行うことになり,あまり感心できません.

(プログラム)
/**************************************/
/* 3つのデータの最大値と最小値の計算 */
/*      coded by Y.Suganuma           */
/**************************************/
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		double a, b, c, amin, amax;
		try {
					// データの入力
			System.out.print("1つ目のデータを入力して下さい ");
			a = Double.parseDouble(in.readLine());
			System.out.print("2つ目のデータを入力して下さい ");
			b = Double.parseDouble(in.readLine());
			System.out.print("3つ目のデータを入力して下さい ");
			c = Double.parseDouble(in.readLine());
					// a>bの場合
			if (a > b) {
				if (c > a) {
					amax = c;
					amin = b;
				}
				else {
					amax = a;
					if (c < b)
						amin = c;
					else
						amin = b;
				}
			}
					// a≦bの場合
			else {
				if (c > b) {
					amax = c;
					amin = a;
				}
				else {
					amax = b;
					if (c < a)
						amin = c;
					else
						amin = a;
				}
			}
					// 出力
			System.out.println("最大値="+ amax + "  最小値=" + amin);
		}
		catch (IOException ignored) {}
	}
}
			

  データの数が増えた場合,上の方法は非常に面倒になります.以下のように書いた方がより一般的であり,また,理解し易いと思います.

(プログラム)
import java.io.*;
public class Test1 {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		double a, b, c, amin, amax;
		try {
					// データの入力
			System.out.print("1つ目のデータを入力して下さい ");
			a = Double.parseDouble(in.readLine());
			System.out.print("2つ目のデータを入力して下さい ");
			b = Double.parseDouble(in.readLine());
			System.out.print("3つ目のデータを入力して下さい ");
			c = Double.parseDouble(in.readLine());
					// 初期設定
			amax = a;
			amin = a;
					// 残りの2つのデータと比較する
			if (b > amax)
				amax = b;
			else {
				if (b < amin)
					amin = b;
			}

			if (c > amax)
				amax = c;
			else {
				if (c < amin)
					amin = c;
			}
					// 出力
			System.out.println("最大値="+ amax + "  最小値=" + amin);
		}
		catch (IOException ignored) {}
	}
}
			

(プログラム例 5.4 ) データの比較  ( A ~ E,及び,F ~ J の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次のプログラムは,入力されたデータを x,y,および,z に代入されている値と比較し,そのどれと等しいかを出力しています.

(プログラム)
/****************************/
/* データの比較             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		int x = 10, y = 20, z = 30;
		int data, sw;
		try {
					// データの入力
			System.out.print("データを入力して下さい ");
			data = Integer.parseInt(in.readLine());
					// 判定と出力
			if (data == x)
				System.out.println("xと等しい");
			else {
				if (data == y)
					System.out.println("yと等しい");
				else {
					if (data == z)
						System.out.println("zと等しい");
					else
						System.out.println("いずれとも等しくない");
				}
			}
		}
		catch (IOException ignored) {}
	}
}
			

  この例ではそれほどではありませんが,一般に,if 文のネストが深くなるとプログラムが見にくくなります.そのような意味で,この例のような場合は,「else if」の構文を利用して,以下のように書いた方がすっきりします.

(プログラム)
/****************************/
/* データの比較             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
public class Test1 {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		int x = 10, y = 20, z = 30;
		int data, sw;
		try {
					// データの入力
			System.out.print("データを入力して下さい ");
			data = Integer.parseInt(in.readLine());
					// 判定と出力
			if (data == x)
				System.out.println("xと等しい");
			else if (data == y)
				System.out.println("yと等しい");
			else if (data == z)
				System.out.println("zと等しい");
			else
				System.out.println("いずれとも等しくない");
		}
		catch (IOException ignored) {}
	}
}
			

5.1.2 switch 文

  switch 文の一般形式は以下の通りです.
switch (式) {
	[case 定数式1 :]
		[文1]
	[case 定数式2 :]
		[文2]
	 ・・・・・
	[default :]
		[文n]
}		
  まず,式が評価されます.その値が定数式の値のいずれかに等しければ,それ以降の文が実行されます.もちろん,文 i は,複数の文でも構いません.いずれの定数式の値にも一致しない場合,もし,default キーワードの項があればそれ以降が実行され,そうでなければ,何も実行されず switch 文以降の文が実行されます.

(プログラム例 5.5 ) データの比較( switch 文)  ( A ~ C の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次のプログラムは,入力されたデータを x,y,および,z に代入されている値と比較し,そのどれと等しいかを出力しています.プログラムの中に,break 文が使用されていますが,break 文はその文に至った時点で強制的に switch 文を抜け出すための文です.このプログラムに対して,20 を入力すると,

yと等しい

と出力されますが,もし,break 文が全くない場合は,この出力文以降がすべて実行されるため,

yと等しい
zと等しい
いずれとも等しくない

のすべての文が出力されてしまいます.

  このプログラムのように,if 文を使用して変数 sw に値を代入することなしに,
switch (data) {
	case x :
		printf("xと等しい\n");
		break;
	case y :
		printf("yと等しい\n");
		break;
	case z :
		printf("zと等しい\n");
		break;
	default :
		printf("いずれとも等しくない\n");
}		
のように書ければ良いのですが,case の後には定数式しか許されていないため,不可能です.もちろん,この例の場合には,x,y,および,z に代入されている値を case の後に直接書けば可能ですが,これらの変数に何が代入されているのかが分からないようなときには,採用できない方法です.

(プログラム)
/****************************/
/* データの比較             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		int x = 10, y = 20, z = 30;
		int data, sw;
		try {
					// データの入力と判定準備
			System.out.print("データを入力して下さい ");
			data = Integer.parseInt(in.readLine());
			if (data == x)
				sw = 0;
			else {
				if (data == y)
					sw = 1;
				else
					sw = (data == z) ? 2 : 3;
			}
					// 判定と出力
			switch (sw) {
				case 0 :
					System.out.println("xと等しい");
					break;
				case 1 :
					System.out.println("yと等しい");
					break;
				case 2 :
					System.out.println("zと等しい");
					break;
				default :
					System.out.println("いずれとも等しくない");
			}
		}
		catch (IOException ignored) {}
	}
}
			

5.2 繰り返し

5.2.1 繰り返し文

  プログラムによっては,同じ手順を何回も繰り返して行いたいような場合がよく起こります.for 文は,その様なときに使用します.例えば,5 つのデータを読み込みその和を計算する場合,前節までの方法を使用すれば次のようになります.

import java.io.*;
public class Test {
	public static void main(String args[]) throws IOException
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		double data;
		double sum = 0.0;
		data = Double.parseDouble(in.readLine());
		sum += data;
		data = Double.parseDouble(in.readLine());
		sum += data;
		data = Double.parseDouble(in.readLine());
		sum += data;
		data = Double.parseDouble(in.readLine());
		sum += data;
		data = Double.parseDouble(in.readLine());
		sum += data;
		System.out.println("和=" + sum);
	}
}
		

  しかし,5 つ程度のデータであれば,上の方法でも可能ですが,データの数が多くなると困難になります.そこで,このプログラムは,for 文を使用することによって,次のようにより簡単に書くことができます.

01	import java.io.*;
02	public class Test {
03		public static void main(String args[]) throws IOException
04		{
05			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
06			double data;
07			double sum = 0.0;
08			for (int i1 = 0; i1 < 5; i1++) {
09				data = Double.parseDouble(in.readLine());
10				sum += data;
11			}
12			System.out.println("和=" + sum);
13		}
14	}
		
  なお,上のプログラムでは,変数 i1 に対する型宣言を for 文の中( 8 行目,C ではできませんが C++ では可)で行っていますが,7 行目以前で行っても構いません.そのようにすれば,変数 i1 は,その宣言が行われた以降で有効になります.しかし,このプログラムのように,for 文の中で型宣言を行うと,その変数は,for 文の中( {} で囲まれたブロック内)のその変数が宣言された以降だけで有効になります.この例においては,08 行目~ 11 行目の間だけで有効になりますので,12 行目以降において変数 i1 を参照しようとすれば,変数 i1 は定義されていないとみなされコンパイルエラーになります.同様に,変数 in や data も for 文の中で宣言可能です.上のプログラムでは,09 行目と 10 行目の等号がそろえて記述してあり,見やすいと思います.しかし,変数 in や data の定義をここに持ってくると,見にくくなるのではないでしょうか.そのような点も考慮しながら型宣言を行った方が良いと思います.

  上で述べたことは,先に述べた if 文,
if (論理式) {
	文1(複数の文も可)
}
else {
	文2(複数の文も可)
}			
においても同様です.文1や文2の中で型宣言が行われると,その変数の有効範囲は文1や文2において型宣言が行われた以降( {} で囲まれたブロック内)だけで有効になります.なお,このような宣言方法は,C/C++ においても可能です.ただし,C/C++ とは異なり,あるブロックで宣言された変数と同じ名前の変数を,その内側のブロックで型宣言を行うことは許されません.

  for 文の一般的形式は以下の通りです.
for (式1; 式2; 式3) {
	文(複数の文も可)
}
 ・・・・・		
  for 文に入ると,まず,式 1 が実行されます.式 1 は,通常,for 文の繰り返し回数を制御するため等の初期設定を行う式であり,for 文の最初に 1 回だけ実行されます.次に,式 2 (論理式)の値が評価され,もし真であれば文が実行されます.そして,式 3 が実行されます.再び,式 2 が評価され,その値が真である限り,文と式 3 の実行が繰り返されます.式 2 の値が偽になると,文と式 3 は実行されず,「・・・」以下の文が実行されることになります( for 文の外に出る).

  for 文において,式 1 と式 3 を省略することは可能(「;」は省略できない)ですが,通常,式 2 を省略することはできません(省略すると,無限ループになってしまう).

  for 文と同様な機能を持つ文として,while 文do while 文があります.while 文,及び,do while 文の一般形式は以下の通りです.
<while文>
	while (式) {
		文(複数の文も可)
	}
	 ・・・・・		
<do while文>
	do {
		文(複数の文も可)
	} while (式) ;
	 ・・・・・		
  while 文では,式(論理式)の値が真である限り,文の実行が繰り返されることになります.while 文と do while 文の違いは,式の評価が,文を実行する最初に行われるか,または,後で行われるかの違いです.do while 文では,式の評価が後で行われるため,do while 文の開始時に式が偽であっても,文が少なくとも 1 回は実行されることになります.

  先に述べた for 文は,while 文を使用して,次のように書くこともできます.どちらの表現方法を使用するかは趣味の問題ですが,問題に応じて,理解しやすいプログラムになると思われる方を使用して下さい.
式1;
while (式2) {
	文(複数の文も可)
	式3;
}		
  このように,for 文,while 文,及び,do while 文はほぼ等価ですので,以下の説明では,基本的に,for 文を使用して説明を行います( while 文や do while 文に対しても同様の議論が成立します).

  if 文と同様,for 文の中が 1 文だけの場合は,{ } を省略可能です.また,次の例のように,for 文の中に別の for 文を書くこともできます( for 文のネスト).
for (式1; 式2; 式3) {
	・・・・・
	for (式4; 式5; 式6) {
		・・・・・
	}
	・・・・・
}		
  また,if 文と同じように,プログラムを読み易くするため,for 文内の文は,次の例のように,何列か段を下げて(字下げをして)書くようにして下さい.
for (i1 = 0; i1 < 10; i1 = i1+1) {
	a = b + c;
	for (i2 = 0; i2 < 5; i2 = i2+1) {
		bcd = a / y;
		aa  = b;
		・・・・・・・・
	}
	sum = c + d;
}		
(プログラム例 5.6 ) 平均値の計算  ( A ~ J ,及び,K ~ U の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  以下に,n 人の英語と数学の点数から,それらの平均点を計算するプログラムを,for 文を使用して書いた例を示します.

(プログラム)
/****************************/
/* 平均値の計算             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.util.*;
public class Test1 {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		double sum1, sum2;
		int n, x, y;
		String line;
		StringTokenizer str;
					// 初期設定
		sum1 = 0.0;
		sum2 = 0.0;
		n    = 0;
		try {
					// データの数の読み込み
			System.out.print("人数は? ");
			n = Integer.parseInt(in.readLine());
					// データの読み込み
			for (int i1 = 0; i1 < n; i1++) {
				System.out.print("英語と数学の点は? ");
				line = in.readLine();
				str  = new StringTokenizer(line, " ");
				x    = Integer.parseInt(str.nextToken());
				y    = Integer.parseInt(str.nextToken());
				sum1 += x;
				sum2 += y;
			}
		}
		catch (IOException ignored) {}
					// 結果の計算と出力
		if (n <= 0)
			System.out.println("データがない!");
		else {
			double mean1 = sum1 / n;
			double mean2 = sum2 / n;
			System.out.println("   英語=" + mean1 + " 数学=" + mean2);
		}
	}
}
			

16,17 行目

  変数 sum1 と sum2 に対する初期設定を行っています.これらの変数は,30 及び 31 行目から明らかなように,各科目の合計点を求めるためのものです.通常,プログラム内で宣言された変数の値は,何らかの形で代入が行われない限り,どのような値になっているかは不明です.もし,これらの変数に 0 以外の値が入っていると,誤った合計計算を行うことになります.そこで,必ず,このような初期設定が必要になります.もちろん,このプログラムの場合は型宣言文の中で初期設定を行っても構いませんが,常に型宣言文の中で行っておけばよいというものではありません.そのような意味で,多少余分な文を書くことにはなりますが,必要な箇所で代入文によって行うような癖を付けた方がよいと思います.

  また,これらの文は,sum1 = 0 というように書いても正しく実行されます.しかし,変数 sum1 の型は double であるということを常に意識し,誤った型変換等を行わないためにも,0.0 というように,対応する正しい定数表現で記述した方が良いと思います.

18 行目

  変数 n に対しても,12 行目で行っても構いませんが,必ず初期設定が必要です.初期設定をしなくても,22 行目において入力されるため,アルゴリズム的には問題ないのですが,入力が内側の try ブロックの中で行われるため,初期設定を行わないと,Java コンパイラはエラーメッセージを出力します.try や catch を使用せずにプログラムを書けば,宣言と入力が同じブロック内となるため,あえて初期設定をする必要はありません.

24 行目

  この for 文によって,まず,変数 i1 が 0 に初期設定され,25 から 31 行目までの文が,条件「 i1 < n 」が満足される間繰り返されます.25 から 31 行目が実行される毎に,式 i1++ によって,変数 i1 の値が 1 づつ増加しますので,結局,25 から 31 行目の文が n 回繰り返されることになります.

36 行目

  もし,人数 n が 0 以下の場合,39,40 行目で行っている平均を求める操作が無意味なものになりますので,この if 文によってそのような場合を除外しています.特に,n の値が 0 の場合は,0 で割ることになり,プログラムの実行が停止してしまいます.このように,0 で割る可能性があるような場合は,0 でないことをチェックしておいた方がよいと思います.

  参考のため,上のプログラムを while 文を使用して書き直したものを以下に示します.どちらのプログラムも正しく動作しますが,このように繰り返し回数が明確になっているような場合は,for 文を使用した方が理解しやすいのではないかと思います.

(プログラム)
/****************************/
/* 平均値の計算             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;
import java.util.*;
public class Test2 {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		double sum1, sum2;
		int n, x, y;
		String line;
		StringTokenizer str;
					// 初期設定
		sum1 = 0.0;
		sum2 = 0.0;
		n    = 0;
		try {
					// データの数の読み込み
			System.out.print("人数は? ");
			n = Integer.parseInt(in.readLine());
					// データの読み込み
			int i1 = 0;
			while (i1 < n) {
				System.out.print("英語と数学の点は? ");
				line = in.readLine();
				str  = new StringTokenizer(line, " ");
				x    = Integer.parseInt(str.nextToken());
				y    = Integer.parseInt(str.nextToken());
				sum1 += x;
				sum2 += y;
				i1++;
			}
		}
		catch (IOException ignored) {}
					// 結果の計算と出力
		if (n <= 0)
			System.out.println("データがない!");
		else {
			double mean1 = sum1 / n;
			double mean2 = sum2 / n;
			System.out.println("   英語=" + mean1 + " 数学=" + mean2);
		}
	}
}
			

  しかし,次に示す例のように,人数を前もって入力せず,英語または数学の点数として負の値を入力した時点でデータ入力を終了したいような場合は,while 文の方がすっきり記述できるかもしれません.17 行目~ 21 行目と 26 行目~ 30 行目では,全く同じ処理を行っていますが,その理由について考えてみてください.

01	import java.io.*;
02	import java.util.*;
03	public class Test {
04		public static void main(String args[])
05		{
06			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
07			double sum1, sum2;
08			int n, x, y;
09			String line;
10			StringTokenizer str;
11						// 初期設定
12			sum1 = 0.0;
13			sum2 = 0.0;
14			n    = 0;
15			try {
16						// データの読み込み
17				System.out.print("英語と数学の点は? ");
18				line = in.readLine();
19				str  = new StringTokenizer(line, " ");
20				x    = Integer.parseInt(str.nextToken());
21				y    = Integer.parseInt(str.nextToken());
22				while (x >= 0 && y >= 0) {
23					n++;
24					sum1 += x;
25					sum2 += y;
26					System.out.print("英語と数学の点は? ");
27					line = in.readLine();
28					str  = new StringTokenizer(line, " ");
29					x    = Integer.parseInt(str.nextToken());
30					y    = Integer.parseInt(str.nextToken());
31				}
32			}
33			catch (IOException ignored) {}
34						// 結果の計算と出力
35			if (n <= 0)
36				System.out.println("データがない!");
37			else {
38				double mean1 = sum1 / n;
39				double mean2 = sum2 / n;
40				System.out.println("   英語=" + mean1 + " 数学=" + mean2);
41			}
42		}
43	}
		

  上と同じプログラムを do while 文を使用して記述すると以下に示すようになります.一見,こちらの方がよいプログラムのように見えますが,「 x >= 0 && y >= 0 」の判定を余分に行っていることになり,計算時間の点からあまり好ましくありません.

01	import java.io.*;
02	import java.util.*;
03	public class Test {
04		public static void main(String args[])
05		{
06			BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
07			double sum1, sum2;
08			int n, x, y;
09			String line;
10			StringTokenizer str;
11						// 初期設定
12			sum1 = 0.0;
13			sum2 = 0.0;
14			n    = 0;
15			try {
16						// データの読み込み
17				do {
18					System.out.print("英語と数学の点は? ");
19					line = in.readLine();
20					str  = new StringTokenizer(line, " ");
21					x    = Integer.parseInt(str.nextToken());
22					y    = Integer.parseInt(str.nextToken());
23					if (x >= 0 && y >= 0) {
24						n++;
25						sum1 += x;
26						sum2 += y;
27					}
28				} while (x >= 0 && y >= 0);
29			}
30			catch (IOException ignored) {}
31						// 結果の計算と出力
32			if (n <= 0)
33				System.out.println("データがない!");
34			else {
35				double mean1 = sum1 / n;
36				double mean2 = sum2 / n;
37				System.out.println("   英語=" + mean1 + " 数学=" + mean2);
38			}
39		}
40	}
		

(プログラム例 5.7 ) ファイル入出力 

  上の例では,平均を計算する人数があらかじめ分かっていました.しかし,英語と数学の点がファイルに保存されており,その人数(データの数)が分からないような場合はどのようにしたらよいでしょうか.次のプログラムはそのような場合の例です.今,あるファイル「input」に英語と数学の点が,

23 45
34 99
・・・・・

のような形で,任意の数だけ保存されているものとします.そして,結果もファイル「output」に保存するものとします.

01	/************************************/
02	/* ファイル入出力(平均値の計算後) */
03	/*      coded by Y.Suganuma         */
04	/************************************/
05	import java.io.*;
06	import java.util.*;
07	
08	public class Test {
09		public static void main(String args[]) throws IOException
10		{
11		/*
12				 データの読み込み
13		*/
14			BufferedReader in = new BufferedReader(new FileReader("input"));
15			double sum1 = 0.0, sum2 = 0.0;
16			String line;   // 1行文の文字列
17			int n = 0;
18			while ((line = in.readLine()) != null) {
19				StringTokenizer str = new StringTokenizer(line, " ");
20				sum1 += Double.parseDouble(str.nextToken());
21				sum2 += Double.parseDouble(str.nextToken());
22				n++;
23			}
24			in.close();
25		/*
26				 結果の計算と出力
27		*/
28			if (n <= 0)
29				System.out.println("データがない!");
30			else {
31				double mean1 = sum1 / n;
32				double mean2 = sum2 / n;
33				PrintStream out = new PrintStream(new FileOutputStream("output"));
34				out.println("人数 " + n + " 英語=" + mean1 + " 数学=" + mean2);
35				out.close();
36			}
37		}
38	}
		
14 行目

  BufferedReader クラスFileReader クラスを使用して,ファイルから読み込み処理を行うためのオブジェクト in を生成しています.

17 行目

  変数 n はデータの数(人数)を数えるためのカウンタです.一組のデータを読む度に,22 行目において 1 づつ増加させています.そのため,必ず,初期設定が必要です.

18 行目

  ここでは,繰り返し制御のため,while 文を使用しています.この例の場合は,while 文の方が for 文より好ましいと思います.while 文の中の式の意味は,データが存在する( null でない)間,1 行文のデータ(文字列)を変数 line に読み込み,19 ~ 22 行目の文を繰り返すことを意味しています.

19 行目~ 21 行目

  変数 line に読み込まれた 1 行文のデータを,StringTokenizer クラスを利用して個々のデータに分離し,それらを double 型に変換した後,和に加えています.

24 行目

  入力データを読み終え,ファイルを必要としなくなったのでその終了処理を行って(閉じて)います.プログラムの実行が終了すると使用していたファイルはすべて自動的に閉じられるため,このプログラムでは必要性は少ないですが,一般的に,使用し終わったら閉じておいた方が良いと思います.

33 行目~ 35 行目

  出力ファイルに対する入力ファイルと同様の処理です.読み込みか,書き込みかの違いです.

(プログラム例 5.8 ) for 文のネスト  ( A ~ F の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次に,for 文のネストの例を示します.今,ある学年に,n クラスあったとします.そして,各クラスには m 人(クラス毎に異なる)の生徒がおり,全員に対しある試験を実施したとします.このとき,平均値が最も高いクラス番号( 1 クラスだけであるとします)とその平均値を出力するプログラムは,例えば,以下のようになります.

  この例により,for 文のネスト,変数の初期設定等を理解して下さい.また,このプログラムでは,色々な場所で変数の定義を行っていますので,それらの変数の有効範囲にも注意して下さい.例えば,i1 は 19 行目~ 38 行目,i2 は 26 行目~ 30 行目,m は 22 行目~ 37 行目,mean は 24 行目~ 37 行目,x は 28 行目~ 29 行目で有効となります.それ以外では,これらの変数は定義されていないとみなされ,使用できません.

(プログラム)
/************************************/
/* クラス平均と最も良いクラスの出力 */
/*      coded by Y.Suganuma         */
/************************************/
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		double max = 0.0;
		int max_c = 0;
		try {
					// データの入力と平均値の計算
			System.out.print("クラスの数は? ");
			int n = Integer.parseInt(in.readLine()); 
							// クラスの数だけ繰り返す
			for (int i1 = 0; i1 < n; i1++) {
				System.out.print((i1+1) + " 番目のクラスの人数は ");
				int m       = Integer.parseInt(in.readLine());
				double mean = 0.0;   // この初期設定はここで必要
									// クラスの人数だけ繰り返す
				for (int i2 = 0; i2 < m; i2++) {
					System.out.print("   " + (i2+1) + " 番目の人の点数は ");
					double x = Double.parseDouble(in.readLine());
					mean    += x;
				}
				mean /= m;
				if (i1 == 0 || mean > max) {
					max   = mean;
					max_c = i1 + 1;
				}
			}
		}
		catch (IOException ignored) {}
					// 結果の出力
		System.out.println("最大平均値はクラス " + max_c + " の " + max + " 点");
	}
}
			

10,11 行目

  アルゴリズム的には,28 行目~ 31 行目からも明らかなように,この位置で初期設定をしておかなくても,これらの変数には必ず適切な値が設定されます.しかし,この位置でこれらの変数の初期設定を行っておかないと(どのような値で初期設定しておいても良い),Java のコンパイラは初期設定されていない可能性があるというエラーメッセージを出力し,コンパイルしてくれません.アルゴリズムの正否をコンパイラが判定することは不可能であることを考えると,余りにも乱暴な考え方ではないかと思います.やはり,C/C++ のように,警告メッセージに留めるべきだと思います.何も考えずに,変数を定義した時点で初期設定を行い,それでよしとするようなことが発生しやすくなります.例えば,変数 mean に対して,10 行目で定義と初期設定を行い,20 行目を記述しなかった場合,何のエラーメッセージも出力されません.しかし,明らかに,アルゴリズムとして間違っています.

  また,Java の場合,変数の型宣言だけを行い,その変数を使用しなくても何のメッセージも出力されません.少なくとも,警告メッセージは出力すべきではないでしょうか.

17 行目

  この for 文により,クラスの数だけ,17 ~ 32 行目までを繰り返します.

22 行目

  この for 文により,各クラスの人数だけ,22 ~ 26 行目までを繰り返します.

28 ~ 31 行目

  変数 i1 の値が 0 ( 1 番目のクラスであることを示す),または,上で計算した変数 mean の値(現在のクラスの平均値)が,変数 max の値より大きいときは,変数 max の値を変数 mean の値で置き換え,かつ,そのクラス番号( i1 + 1 )を変数 max_c に記憶します.この記述によって,最初に計算したクラスに対しては,無条件にそのクラス番号と平均値を max_c と max に保存します.従って,10,11 行目において初期設定を行っていなくても,正しい結果が得られるはずです.

(プログラム例 5.9 ) 入力の繰り返し( do while )  ( A ~ D の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  要求するデータ( 0 以上のデータ)が入力されるまで,データの入力を繰り返し促したいような場合が存在します.この例では,do while 文を使用して,その処理を行っています.もちろん,for 文や while 文を使用して書くことも可能ですが,do while 文の方が書きやすいかもしれません.

(プログラム)
/**************************************/
/* 正しいデータの再入力(do-while文) */
/*      coded by Y.Suganuma           */
/**************************************/
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		int x, y;
		try {
			do {
				System.out.print("1番目の正の整数を入力して下さい ");
				x = Integer.parseInt(in.readLine());
				System.out.print("2番目の正の整数を入力して下さい ");
				y = Integer.parseInt(in.readLine());
			} while (x <= 0 || y <= 0);
			System.out.println("和は=" + (x+y));
		}
		catch (IOException ignored) {}
	}
}
			

(プログラム例 5.10 ) 最大値(初期設定)  ( A ~ D の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  最大値を求める基本的なアルゴリズムは以下の通りです.まず,最大値を保存する変数,例えば max を適当な値で初期設定しておきます.次に,最大値を求めるデータ群の中の各データと max に代入されている値とを比較し,もし,比較したデータの方が max に代入されている値より大きければ,そのデータを max に代入します.これをすべてのデータに対して繰り返せば最大値が求まることになります.つまり,以下のようにプログラムすればよいわけです(データの数は 5 とし,各データはキーボードから入力されるものとしています).

/****************************/
/* 最大値の計算             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;

public class Test {
	public static void main(String args[]) throws IOException
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

		int n = 5, max = 0;
		for (int i1 = 0; i1 < n; i1++) {
			System.out.print("データを入力してください ");
			int x = Integer.parseInt(in.readLine());
			if (x > max)
				max = x;
		}

		System.out.println("   最大値=" + max);
	}
}
		

  上のプログラムに問題は全くなさそうに見えます.しかし,負のデータだけを入力した場合について考えてみてください.最大値は 0 であるという答えが得られるはずです.明らかに,誤っています.なぜなら,変数 max に初期設定すべき値は,求めるべき最大値より必ず小さくなければならないからです.しかし,求めるべき最大値は不明です.どのようにしたら良いでしょうか.一つの方法は,以下のプログラムのように,最初のデータを max に代入しておく方法です.

/****************************/
/* 最大値の計算             */
/*      coded by Y.Suganuma */
/****************************/
import java.io.*;

public class Test {
	public static void main(String args[]) throws IOException
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

		System.out.print("データを入力してください ");
		int max = Integer.parseInt(in.readLine());   // 最初のデータでmaxを初期化

		int n = 5;
		for (int i1 = 1; i1 < n; i1++) {   // i1を1から始める
			System.out.print("データを入力してください ");
			int x = Integer.parseInt(in.readLine());
			if (x > max)
				max = x;
		}

		System.out.println("   最大値=" + max);
	}
}
		

  上のプログラムは,どのようなデータを与えても,正しく最大値を出力してくれるはずです.それでは,問題を少し変えて,「与えられたデータの内,負のデータの最大値を求めよ」というようにしたらどうでしょうか.max とデータを比較している部分を,
if (x < 0 && x > max)		
のように変えてやればうまくいくよう思われるかもしれません.たしかに,最初のデータが負であるときは正しく動きます.しかし,そうでないときは誤った最大値を出力してしまいます.これを回避する一つの方法は,以下のプログラムのように,変数 max が初期化されたか否かを示す指標(変数 sw )を設けてやることです.明らかに,この例の場合,変数 max に対する初期設定は不要です.しかし,プログラム例 5.8 と同様,初期設定を行わないとコンパイルエラーになり,コンパイルしてくれません.

(プログラム)
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		int n = 5, max = 0, sw = 0;   // maxに対して任意の値で初期設定する必要
		try {
			for (int i1 = 0; i1 < n; i1++) {
				System.out.print("データを入力してください ");
				int x = Integer.parseInt(in.readLine());
				if (x < 0 && (sw == 0 || x > max)) {
					max = x;
					sw  = 1;
				}
			}
			System.out.println("   最大値=" + max);
		}
		catch (IOException ignored) {}
	}
}
			

(プログラム例 5.11 ) for 文,while 文,do while 文の比較 

  次の 3 つのプログラムは,for 文( 001 行目~ 029 行目),while 文( 030 行目~ 060 行目),及び,do while 文( 061 行目~ 107 行目)を使用して,同じ内容の処理を行っています.(1)においては,0 以上の数値が入力されるまで,入力データを要求し続けます.(2)においては,(1)で入力された数 no だけ「 * 」を出力すると共に,1 から no までの和を求めています.no の値が 0 の場合は,和だけが出力されます.この例では,for 文における i の初期値を 1 に設定していますが,コメント( 012,014 行目)に示したような形式でも構いません.(3)においては,データとして 0 を入力するまでの複数のデータの和を求めています.

  do while 文を使用した場合,一見,// によってコメント化した方法( 072 行目~ 079 行目,093 行目~ 097 行目)で良さそうですが,do 以下の内容が必ず 1 回は実行されるため,(2)に対しては,no の値が 0 の場合でも * が 1 個出力されてしまい,また,(3)に対しては,最初のデータとして 0 を入力しても,再度,「データ?」という入力促進メッセージが出力されてしまいます.

import java.io.*;
import java.util.*;
/*
	for 文
*/
001	public class Test {
002		public static void main(String args[])
003		{
004				// (1)入力
005			int i, no = -1, sum1 = 0, sum2 = 0;
006			Scanner sc = new Scanner(System.in);
007			for (; no < 0; ) {
008				System.out.printf("0以上の整数を入力してください ");
009				no = sc.nextInt();
010			}
011				// (2)*と和1
012			for (i = 1; i <= no; i++) {   // for (i = 0; i < no; i++) {
013				System.out.printf("*");
014				sum1 += i;   // sum1 += (i + 1);
015			}
016			if (no > 0)
017				System.out.printf("\n");
018			System.out.printf("sum1 = %d\n", sum1);
019				// (3)和2
020			System.out.printf("データ? ");
021			i = sc.nextInt();
022			for (; i != 0; ) {
023				sum2 += i;
024				System.out.printf("データ? ");
025				i = sc.nextInt();
026			}
027			System.out.printf("sum2 = %d\n", sum2);
028		}
029	}
/*
	while 文
*/
030	public class Test {
031		public static void main(String args[])
032		{
033				// (1)入力
034			int i, no = -1, sum1 = 0, sum2 = 0;
035			Scanner sc = new Scanner(System.in);
036			while (no < 0) {
037				System.out.printf("0以上の整数を入力してください ");
038				no = sc.nextInt();
039			}
040				// (2)*と和1
041			i = 1;
042			while (i <= no) {
043				System.out.printf("*");
044				sum1 += i;
045				i++;
046			}
047			if (no > 0)
048				System.out.printf("\n");
049			System.out.printf("sum1 = %d\n", sum1);
050				// (3)和2
051			System.out.printf("データ? ");
052			i = sc.nextInt();
053			while (i != 0) {
054				sum2 += i;
055				System.out.printf("データ? ");
056				i = sc.nextInt();
057			}
058			System.out.printf("sum2 = %d\n", sum2);
059		}
060	}
/*
	do while文
*/
061	public class Test {
062		public static void main(String args[])
063		{
064				// (1)入力
065			int i, no = -1, sum1 = 0, sum2 = 0;   // noに対する初期設定は必要なし
066			Scanner sc = new Scanner(System.in);
067			do {
068				System.out.printf("0以上の整数を入力してください ");
069				no = sc.nextInt();
070			} while (no < 0);
071				// (2)*と和1
072	//		i = 1;
073	//		do {
074	//			System.out.printf("*");
075	//			sum1 += i;
076	//			i++;
077	//		} while (i <= no);
078	//		if (no > 0)
079	//			System.out.printf("\n");
080			if (no > 0) {
081				i = 1;
082				do {
083					System.out.printf("*");
084					sum1 += i;
085					i++;
086				} while (i <= no);
087				System.out.printf("\n");
088			}
089			System.out.printf("sum1 = %d\n", sum1);
090				// (3)和2
091			System.out.printf("データ? ");
092			i = sc.nextInt();
093	//		do {
094	//			sum2 += i;
095	//			System.out.printf("データ? ");
096	//			i = sc.nextInt();
097	//		} while (i != 0);
098			if (i != 0) {
099				do {
100					sum2 += i;
101					System.out.printf("データ? ");
102					i = sc.nextInt();
103				} while (i != 0);
104			}
105			System.out.printf("sum2 = %d\n", sum2);
106		}
107	}
		

5.2.2 繰り返しの中断

  通常,繰り返し文は,繰り返し条件が成立しなくなるまで続けられますが,場合によっては,繰り返しの途中でループの外へ出たい場合があります.この節では,そのような場合に使用する文について解説します.

5.2.2.1 break 文

  break 文は,break を囲んでいる最も内側の for 文,while 文,または,do while 文を終了させ,それらの次の文に制御を移します.また,switch においても,しばしば使用されます.

(プログラム例 5.12 ) 繰り返しの中断( break )  ( A ~ D の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次のプログラムは,n 個のデータの和を求めるプログラムですが,負のデータが入力されると,その時点で for ループの外に出ます.

/**********************************/
/* データの和(負のデータで終了) */
/*      coded by Y.Suganuma       */
/**********************************/
import java.io.*;

public class Test {
	public static void main(String args[]) throws IOException
	{
	/*
		 データ数の入力
	*/
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		System.out.print("データ数は? ");
		int n = Integer.parseInt(in.readLine());
	/*
		 和の計算
	*/
		int sum = 0;
		for (int i1 = 0; i1 < n; i1++) {
			System.out.print("   データを入力して下さい ");
			int x = Integer.parseInt(in.readLine());
			if (x < 0)
				break;
			else
				sum += x;
		}
	/*
		 出力
	*/
		System.out.println("和=" + sum);
	}
}
		

  上のプログラムは,break 文を使用せず,以下に示すような方法で書くことも可能です.多重ループから一度に抜け出したいような場合は,各ループ毎に break 文を使用する必要がありますが,この方法を使用すれば,多重ループの外側に一度に抜け出せます.

(プログラム)
import java.io.*;
public class Test {
	public static void main(String args[])
	{
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		int x = 0, sum = 0;   // x の初期化を忘れないこと
		try {
					// データ数の入力
			System.out.print("データ数は? ");
			int n = Integer.parseInt(in.readLine());
					// 和の計算
			for (int i1 = 0; i1 < n && x >= 0; i1++) {
				System.out.print("   データを入力して下さい ");
				x = Integer.parseInt(in.readLine());
				if (x >= 0)
					sum += x;
			}
					// 出力
			System.out.println("和=" + sum);
		}
		catch (IOException ignored) {}
	}
}
			

5.2.2.2 continue 文

  continue 文は,for 文,while 文,または,do while 文本体の残りを実行せずに,次の繰り返しを実行します.break 文と似ていますが,continue 文では,break のように現在の繰り返し自身を終了させるわけではありません.

(プログラム例 5.13 ) 繰り返しの中断( continue ) 

  次のプログラムは,n 個のデータの和を求めるプログラムですが,負のデータが入力された場合はそのデータを除外します.

/**********************************/
/* データの和(負のデータを除外) */
/*      coded by Y.Suganuma       */
/**********************************/
import java.io.*;

public class Test {
	public static void main(String args[]) throws IOException
	{
	/*
		 データ数の入力
	*/
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		System.out.print("データ数は? ");
		int n = Integer.parseInt(in.readLine());
	/*
		 和の計算
	*/
		int sum = 0;
		for (int i1 = 0; i1 < n; i1++) {
			System.out.print("   データを入力して下さい ");
			int x = Integer.parseInt(in.readLine());
			if (x < 0)
				continue;
			else
				sum += x;
		}
	/*
		 出力
	*/
		System.out.println("和=" + sum);
	}
}
		

5.3 変数の有効範囲

  今までも何度か述べましたが,ここでは,メソッド内で型宣言した変数の有効範囲についてまとめておきます.基本的に,メソッド内で宣言された変数の有効範囲は,そのメソッド内だけであることを忘れないでください.

(プログラム例 5.14 ) 変数の有効範囲 

01	/****************************/
02	/* 変数の有効範囲           */
03	/*      coded by Y.Suganuma */
04	/****************************/
05	import java.io.*;
06	import java.util.*;
07	
08	public class Test {
09		public static void main(String args[]) throws IOException
10		{
11			int max;
12			Console con = System.console();
13						// データの入力
14			String line = con.readLine("2つのデータをスペースで区切って入力してください ");
15			StringTokenizer str = new StringTokenizer(line, " ");
16			int a = Integer.parseInt(str.nextToken());
17			int b = Integer.parseInt(str.nextToken());
18						// if 文
19			if (a >= b) {
20				max = a;
21	//			int a = -5;
22				int min = 0;
23				if (a > b)
24					a = b;
25				System.out.println("最小値 = " + min + ",  a = " + a);
26			}
27			else {
28				max = b;
29				int min = a;
30				System.out.println("最小値 = " + min + ",  a = " + a);
31			}
32						// 繰り返し文
33			for (int i1 = a; i1 <= b; i1++) {
34				int x = i1 + 5;
35				System.out.println("x = " + x);
36			}
37						// 出力
38			double x = -2.5;
39			System.out.println("最大値 = " + max + ",  a = " + a + ",  x = " + x);
40	//		System.out.println("最小値 = " + min + " i1 = " + i1);
41		}
42	}
		
11 行目~ 17 行目

  ここでは,6 つの変数( max, con, line, str, a, b )の宣言が行われると共に,max を除く変数への代入(初期設定)も行われています.勿論,宣言と代入を同時に行わず,代入が行われる前に宣言だけを行っておくことも可能です.例えば,11 行目で,a と b の宣言を行っておけば,16,17 行目における int は不要です(付けると,多重定義になり,エラーとなる).こられの変数は,この宣言が行われた以降,main メソッドの最後( 40 行目)まで有効です.

21 行目

  既に 16 行目において変数 a に対する宣言が行われているため,エラーとなります.C++ とは異なり,Java においては,あるブロックで定義された変数と同じ名前の変数を,その内側のブロックで再定義することはできません.ただし,今までの例では使用していませんが,メソッドの外側で宣言された変数に対しては,同じ名前の変数をメソッド内で定義することが可能であり,その有効範囲はメソッド内で,かつ,その変数が定義された以降になります.

22 行目

  変数 min に対する宣言は,if ブロックの内部で行われているため,変数 min の有効範囲は,このブロック内の宣言が行われた以降だけです( 23 行目~ 25 行目).else ブロック内で定義されている 29 行目の変数 min,及び,for ブロック内で定義されている 33 行目の変数 i1,34 行目の変数 x も同様です.これらの変数は,すべて,定義されているブロック内だけで有効なため,40 行目のように,ブロック外で変数 min や i1 を参照しようとするとエラーになります.また,これらの変数が定義された後であっても,それらの変数が定義されたブロックの外であれば,38 行目のように,全く同じ名前の変数を定義することが可能です.

「1 2」を入力したときの出力
最小値 = 1,  a = 1
x = 6
x = 7
最大値 = 2,  a = 1,  x = -2.5			
「2 1」を入力したときの出力
最小値 = 0,  a = 1
x = 6
最大値 = 2,  a = 1,  x = -2.5			

演習問題5

[問1]年齢を読み込み,20 歳以上なら「大人」,そうでなければ「子供」と出力するプログラムを書け.

[問2]一つの整数データを読み込み,その値がゼロなら「0」,正なら「正」,それ以外なら「負」と出力するプログラムを,if 文を使用して書け.

[問3]試験の点数を読み込み,その点数が
60 点未満なら「不可」
60 点以上で 70 点未満なら「可」
70 点以上で 80 点未満なら「良」
80 点以上なら「優」
と出力するプログラムを書け

[問4]時間と分の変換を行うプログラムを書け.つまり,1 時間 20 分なら 80 分,また,90 分なら 1 時間 30 分に変換する.

[問5]閏年の判定を行うプログラムを書け.閏年は,年号が 4 で割り切れ,100 で割り切れない年である.ただし,400 で割り切れる年は含む.

[問6]1 度,2 度,・・・,及び,90 度に対し,各角度とその正弦の値(関数 sin )を出力するプログラムを書け(注:ヘッダファイル math.h も必要).

[問7]次の式の値を計算し,出力するプログラムを書け
(1)1.02+・・・+500.02
(2)1/1 + 1/2 + 1/3 + ・・・ + 1/20

[問8] n(入力)個のデータを読み込み,100 以上のデータ,及び,100 未満のデータの和をそれぞれ求めるプログラムを書け.

[問9]与えられた n 個のデータ内にある正の数と負の数の個数を出力するプログラムを書け.

[問10] n 個の抵抗(入力)を直列または並列に接続したときの抵抗を計算するプログラムを書け.

[問11] n の値を読み込んだ後,n! を計算し出力するプログラムを書け.

[問12] n,r の値を読み込んだ後,nr( = n! / (r! (n - r)!) )を計算するプログラムを書け.

[問13]正の整数値 n を読み込み,偶数の時はその値を 2 で割り,また,奇数の時はその値を 3 倍したものに 1 を加えるという処理を n の値が 1 になるまで繰り返すためのプログラムを書け.ただし,1 回の演算を行う毎に現在の n の値を表示するものとする.

[問14]n(入力)人の試験の点を入力した後,不可,可,良,及び,優の割合(%)を計算し,出力するプログラムを書け.ただし,
不可: 50 点未満
可 : 50 点から 60 点未満
良 : 60 点から 80 点未満
優 : 80 点以上
とする.

[問15] n 人に給与を支払うものとする.n 及び各人の給与の額をファイルから読み込み,すべての人に給与を釣り銭がないように支払うために必要な 10,000 円札,5,000 円札,1,000 円札,500 円硬貨,及び,100 円硬貨の合計枚数を出力するプログラムを書け.ただし,給与の最小単位は 100 円であるものとする.

[問16]九九の表を出力するプログラムを書け.

[問17]正の整数を入力し,それを各桁毎に分解し,それらの数字を正順及び逆順に,間に 1 つ以上の空白をあけて出力するプログラムを書け.例えば,12345 と入力したら,次のように出力することになる.ただし,整数の桁数は最大 9 桁であるとする.
1 2 3 4 5
5 4 3 2 1

[問18]整数型データの中で 1 になっているビットの数を出力するプログラムを書け.

[問19]複数個(未知)の実数データをファイルから読み込み,その最大値と最小値を出力するプログラムを書け.

[問20]ある学年に n(入力)クラスあり,各クラスには m(入力,クラス毎に異なる)人の生徒がいるものとする.全員に対しある試験を実施したとき,学年で最高点をとった生徒の点数及びその生徒が属するクラス番号を出力するプログラムを書け(最高点の生徒は一人だけであるとする).

[問21]ニュートン法により次式の根を求めるためのプログラムを書け.
f(x) = ex - 3x = 0
ただし,ニュートン法とは,関数 f(x) が単調連続で変曲点が無く,かつ,微分可能であるとき利用できる方法であり,根の適当な初期値 x0 から始めて,反復公式
xn+1 = xn - f(xn) / f'(xn)
を繰り返すことによって非線形方程式の解を求める方法である.この方法の幾何学的意味は右図に示すとおりである.収束判定の条件としては,
|xn+1 - xn| < ε
|f(xn+1) - f(xn)| < ε
|f(xn)| < ε
などがある.

[問22]二分法により次式の根を求めるためのプログラムを書け.
f(x) = ex - 3x = 0
ただし,二分法は,関数 f(x) が区間 [a, b] で連続で,かつ,根が1つだけ存在するとき利用できる方法である.従って,f(a)f(b) < 0 となる.区間 [a, b] の中点 c を
c = 0.5 * (a + b)
で求め,f(c) の値を計算し,f(a)f(c) < 0 なら
b = c,f(b) = f(c)
そうでなければ
a = c,f(a) = f(c)
と置き換え,根の存在区間を半分に縮小する.この操作を,
|b - a| < ε
が満足されるまで繰り返すことによって解を求める.

[問23]台形則により次の関数の任意区間の積分値を計算するプログラムを書け.
f(x) = (2π)-0.5-x*x/2
ただし,台形則は,積分区間[x1, x2]をn個の,幅
h = (x2 - x1) / n
の小区間に分け,各区間の面積を右図のような台形で近似して,積分値を計算する方法である.従って,積分値Sは次のように書ける.
S = 0.5h{f(x1) + 2(f(x1+h) + f(x1+2h) + ・・・ + f(x2-h)) + f(x2)}

情報学部 菅沼ホーム 全体目次 演習解答例 付録 索引