3. switch文を用いたプログラムの流れの分岐
INDEX

目標

  • 条件によって複数の処理の中からいずれかを選択するプログラムをswitch文を使って実現することができる。

予習・復習

 以下のスライドを利用して、予習と復習をしよう。復習では、自分の理解度を確認するために、実際にプログラムを作成し、意図する結果が得られるか確認しよう。
  1. switch文

本日の講義・演習予定

  1. switch文
  2. 乱数
  3. 演習問題
  4. 提出課題
内 容
  1. switch文
  2. 乱数

switch文

switch文

 if else文はその条件式が真か偽かのいずれかに評価されることによって、2つの処理のうちのどちらかを一つだけを処理する構文でした。switch文は、式が整数値として評価され、その値によって処理を選択する構文です。
 以下は、switch文を使って、整数0が入力されると「0です。」、整数1が入力されると「1です。」、整数2が入力されると「2です。」、それ以外の値なら「0,1、2以外の数です。」と表示するプログラム例です。
例 switchNum.c
#include <stdio.h>

int main(void)
{
	int n;
	
	printf("整数>> ");
	scanf("%d", &n);

	switch (n) {
		case 0:
			printf("0です。\n");
			break;
		case 1:
			printf("1です。\n");
			break;
		case 2:
			printf("2です。\n");
			break;
		default:
			printf("0,1,2以外の数です。\n");
	}
	
	return 0;
}
 switch文の構文を見ていきましょう。キーワードswitchの直後のカッコ内に処理を選択するための式を記述します。この式の評価結果(値)によってそれ以降に記述された処理の分岐先が決定します。各分岐先はキーワードcaseではじまり、その直後に評価結果の値に対応する定数が表記されます。式の評価結果に一致する定数のcase文に分岐して処理が行われます。通常、処理の最後にはbreak文を記述して、switch文のコードブロックを抜け出すようにします。また、いずれのcase文の定数とも一致しない場合は、default文が処理されます。
構文:
switch (式) {
	case 定数1:
		式の評価結果が定数1の場合の処理;
		break;
	case 定数2:
		式の評価結果が定数2の場合の処理;
		break;
	・・・
	・・・
	
	case 定数n:
		式の評価結果が定数nの場合の処理;
		break;
	default:
		上記のどの場合にも当て間らなかった場合の処理;
}
if
式の評価結果の値は整数でなければなりません。また、case文に設定できる値は一つの定数であって、複数の値や値の範囲を示す式を使うことはできません。

break文無しで複数の条件を満たす

 月を入力してその季節を表示するプログラムを考えます。3〜5月は春、6〜8月は夏、9〜11月は秋、12〜2月は冬だとします。switch文を使って次のようなプログラムを書いてみました。
例 season.c
#include <stdio.h>

int main(void)
{
	int n;
	
	printf("何月>> ");
	scanf("%d", &n);

	switch (n) {
		case 3:
			printf("春です。\n");
			break;
		case 4:
			printf("春です。\n");
			break;
		case 5:
			printf("春です。\n");
			break;
		case 6:
			printf("夏です。\n");
			break;
		case 7:
			printf("夏です。\n");
			break;
		case 8:
			printf("夏です。\n");
			break;
		case 9:
			printf("秋です。\n");
			break;
		case 10:
			printf("秋です。\n");
			break;
		case 11:
			printf("秋です。\n");
			break;
		case 12:
			printf("冬です。\n");
			break;
		case 1:
			printf("冬です。\n");
			break;
		case 2:
			printf("冬です。\n");
			break;
		default:
			printf("そんな月はありません。\n");
	}
	
	return 0;
}

 正しい結果が得られるプログラムですが、同じ処理がいくつもあり無駄な感じがします。どうにかならないものでしょうか。switch文はbreak文を使ってそのブロックを抜け出すのでした。もし、break文がなかったらどうなるのでしょう。例えば、定数3のcase文にあるbreak文を削除してみます。「春です。」と表示した後にbreak文がないので、その直下の定数4のcase文に処理が以降します。その結果、また、「春です」と表示するのです。つまり、switch文ではbreak文が登場するまで、case文に関わらず処理が継続されることになるのです。これを利用して無駄な処理をなくしたのが、次のプログラム例です。
例 season.c
#include <stdio.h>

int main(void)
{
	int n;
	
	printf("何月>> ");
	scanf("%d", &n);

	switch (n) {
		case 3:
		case 4:
		case 5:
			printf("春です。\n");
			break;
		case 6:
		case 7:
		case 8:
			printf("夏です。\n");
			break;
		case 9:
		case 10:
		case 11:
			printf("秋です。\n");
			break;
		case 12:
		case 1:
		case 2:
			printf("冬です。\n");
			break;
		default:
			printf("そんな月はありません。\n");
	}
	
	return 0;
}

char型を式に使ったswitch文

 文字を扱うchar型は、基本的にデータ幅が1バイトの整数型です。文字を扱うために利用される型ではありますが、文字専用の型というわけでもありません。つまり、整数値の値で分岐先を決定するswitch文の式として利用することもできます。次のプログラム例は半角アルファベットを入力して、母音(a,i,u,e,o)ならばそのひらがなを表示するプログラムです。
例 hiragana.c
#include <stdio.h>

int main(void)
{
	char c;

	printf("> ");
	c = getchar();	//文字の読み込み

	switch(c){
		case 'a':
			printf("あ\n");
			break;
		case 'i':
			printf("い\n");
			break;
		case 'u':
			printf("う\n");
			break;
		case 'e':
			printf("え\n");
			break;
		case 'o':
			printf("お\n");
			break;
		default:
			printf("変換できません。\n");
			break;
	}

	return 0;
}

乱数

乱数

 乱数とは、サイコロを振って出る目のように予測不可能な値、ランダムな値のことを言います。乱数はゲームやシミュレーションなどで予測できない状況を再現するために利用されます。乱数をC言語で生成するためには、標準ライブラリstdlib.hで定義されている関数rand()がよく利用されます。次のプログラムは関数rand()を使って乱数を生成する例です。
randnum.c
#include <stdio.h>	// 入出力関連の関数が定義されているヘッダファイル
#include <stdlib.h>	// 乱数関連の関数が定義されているヘッダファイル
#include <time.h>	// 時間関連の関数が定義されているヘッダファイル

int main(void)
{
	int rand_num;
	
	srand((unsigned)time(NULL));	//時刻の種を植える

	rand_num = rand();		//乱数の生成
	printf("乱数: %d\n", rand_num);

	return 0;
}
 関数rand()によって生成される乱数は本当の意味での乱数とは異なり、ランダムに見えるようにコンピュータによって確定的に計算された値です。これを擬似乱数と言います。毎回異なる値を生成するためには、乱数の元となる"種"の値も変える必要があります。この種の値を設定するための関数がsrand()です。実行毎に異なる乱数を得るために、ここでは刻々と変わる”時刻”を関数srand()を使って植え込んでいるのです。試しに関数srand()をコメント化して無効にしてみてください。すると、関数rand()がいつも同じ値を生成することがわかります。

特定の範囲の乱数を生成する

 関数rand()が生成する値は、0から定数RAND_MAX(環境によって異なる)までの広い範囲の値です。例えば、サイコロの目と同じ1〜6までの値が欲しい時には、以下の例のように剰余演算を使って6で割った余り0〜5を求めてから、これに1を加えます。
dicenum.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	int dice;
	
	srand((unsigned)time(NULL));	//時刻の種を植える

	dice = rand()%6+1;
	printf("1〜6: %d\n", dice);

	return 0;
}


expand_lessBack to TOP

演習問題

  1. 月数を入力して和風月名を表示するプログラムex3-1.cです。空欄を埋めて完成させなさい。
  2. ex3-1.c
    #include <stdio.h>
    
    int main(void)
    {
    	int m;
    
    	printf("何月?>>");
    	scanf("%d", &m);
    
    	[[空欄ア]] {
    		[[空欄イ]]
    			printf("睦月");
    			break;
    		[[空欄ウ]]
    			printf("如月");
    			break;
    		[[空欄エ]]
    			printf("弥生");
    			break;
    		[[空欄オ]]
    			printf("卯月");
    			break;
    		[[空欄カ]]
    			printf("皐月");
    			break;
    		[[空欄キ]]
    			printf("水無月");
    			break;
    		[[空欄ク]]
    			printf("文月");
    			break;
    		[[空欄ケ]]
    			printf("葉月");
    			[[空欄コ]]
    		[[空欄サ]]
    			printf("長月");
    			break;
    		[[空欄シ]]
    			printf("神無月");
    			break;
    		[[空欄ス]]
    			printf("霜月");
    			break;
    		[[空欄セ]]
    			printf("霜月");
    			break;
    		[[空欄ソ]]
    			printf("そんな月はありません。");
    	}
    	printf("\n");
    
    	return 0;
    }
    
  3. 整数を入力して3で割った余りを表示するプログラムex3-2.cです。空欄を埋めて完成させなさい。
  4. ex3-2.c
    #include <stdio.h>
    
    int main(void)
    {
    	int n;
    
    	printf("整数>> ");
    	scanf("%d", &n);
    
    	switch([[空欄ア]]){
    		case [[空欄イ]]:
    			printf("割り切れました。\n");
    			break;
    		case 1 :
    			printf("余は1です。\n");
    			[[空欄ウ]];
    		case 2:
    			printf("余は2です。\n");
    			break;
    	}
    
    	return 0;
    }
    	

  5. おみくじをswitch文を使って実現するプログラムex3-3.cを作成しなさい。ただし、大吉、吉、中吉、小吉、末吉の出現確率をそれぞれ、1/10、1/5、3/10、3/10、1/10とすること。

  6. 次のトランプのナンバーを入力して記号表示するプログラムex3-4.cをswitch文を使って書き換えなさい。一部にif文を使っても良い。

  7. 下記のように、二つの整数と加減乗除剰余(+,-,*,/,%)のいずれかの演算子を入力して、その演算結果を表示するプログラムを作成しなさい。
  8. ex3-4.c
    #include <stdio.h>
    
    int main(void)
    {
    	int x,y;
    	char op;
    
    	printf("整数>> ");
    	scanf("%d",&x);
    	printf("整数>> ");
    	scanf("%d",&y);
    	printf("演算記号(+,-,*,/,%%)>> ");
    	getchar();
    	scanf("%c",&op);
    	
    	・・・
    	ここを埋める
    	・・・
    	
    	return 0;
    }
    	
    ※ scanf("%c",&op)の前にgetchar()が挿入されている理由: 直前のscanf("%d",&y)ではキーボードから入力した整数だけが読み込まれ、入力バッファには改行(\n)が残ったままになっている。そのため、直後の1文字だけを読み込むscanf("%c",&op)ではこの改行(\n)を読み込んでしまい、演算記号である文字を入力できなくなってしまう。getchar()で改行(\n)を読み込むことで、入力バッファを空にしている。getchar()がある場合と、ない場合とを比較してみると良い。

  9. 西暦年と1〜12月の何かの月を入力して、その月の日数を表示するプログラムをswitch文を使って作成しなさい。閏年も考慮すること。
    1月2月3月4月5月6月7月8月9月12月11月12月
    3128/2931303130313130313031

  10. 整数を入力して、3の倍数であるときは「Fizz」、5の倍数であるときは「Buzz」、15の倍数であるときは「Fizz Buzz」、それ以外のときは入力した数字を表示するプログラムをswitchを使って実現しなさい。

  11. 次に示す範囲の乱数を関数rand()を使って生成するための式を示しなさい。
    (1) 10 から 99 までの整数
    (2) -5 から 5 までの整数
    (3) 0 から 1.0 未満の少数

  12. あなたの手(グー、チョキ、パーのいずれか)を入力してコンピュータと対戦できるじゃんけんプログラムをswitch文を使って実現しなさい。
  13. 3つの抵抗の抵抗値と接続方法を入力して、接続の仕方の違いによる合成抵抗値を表示するプログラムを作成しなさい。

演習問題解答

OPEN ANSWER
  1. 空欄ア swtich (m) 空欄イ〜ケ 1,2,3,4,5,6,7,8 空欄コ break; 空欄サ〜セ 9,10,11,12 空欄ソ default: 


  2. 空欄ア n%2 空欄イ 0 空欄ウ break


  3. 回答例 ex3-3.c
  4. code/3/ex3-3.c

  5. 回答例 ex3-4.c
  6. code/3/ex3-5.c

  7. 回答例 ex3-5.c
  8. code/3/ex3-6.c

  9. 回答例 ex3-6.c
  10. code/3/ex3-7.c

  11. (1)rand()%90+10、(2)5-rand()%11、(3)rand()/(RAND_MAX+1.0)


  12. 回答例 ex3-8.c
  13. code/3/ex3-9.c

    *勝敗判定:グー・チョキ・パーの各手をそれぞれ0,1,2として、(自分の手 - 相手の手 + 3)%3の値は、0が引き分け、1が負け、2が勝ちになる。全てのパターンを書き出して、調べてみると良い。

expand_lessBack to TOP

提出課題

以下の各プログラムを作成しなさい。但し、switch文を使って実現すること。
  • 課題1
  • トランプのカードの番号を入力して、1、11、12,13はそれぞれアルファベットのA、J、Q、Kと出力し、それ以外は同じ数字で表示するプログラム。

  • 課題2
  • グー、チョキ、パーのいずれかを乱数を使って表示するプログラム。ただし、グー、チョキ、パーの各手の出現比率を2:3:5とすること。

  • 課題3
  • 正の整数を入力して、3の倍数ならば「Fizz」、5の倍数ならば「Buzz」、15の倍数ならば「Fizz Buzz」と表示するプログラム。


  • [提出方法]
    1. ideone.comを利用して作成した課題プログラムのURLをCoursePowerへ提出のこと。
    2. 詳細はスライド「ideoneの使い方」参照のこと。

  • [評価について]
  • プログラムの内容の評価とは別に以下の要件を満たすことを評価の前提とする。
    1. C言語で記述されていること。
    2. ソースコードファイルのコンパイル結果に、ワーニングやエラーが出力されていないこと。
    3. 所定の実行結果が得られるていること。
    4. ソースコードは、インデントや適当な改行が施された見やすい状態であること。

  • [提出期限]
  • 2023年 5月1日(月)までとする。ただし、以降の提出も受け付ける。