joho1-2016の日記

情報処理実習1の解説ブログです.皆さんが課題を解く時の助けになれば幸いです.

第4回 制御文2

解説を始める前に,5組・6組ともに命名規則を守らずに提出している学生が未だにいます.
一度全体での注意をしたので,今後命名規則を守らない回の提出物は中身を確認せず採点対象外となるので,提出前にもう1度自分の提出ファイル(zipファイルだけでなくcppファイルも含めて)の名前を確認しましょう。

第4回 制御文2のおさらいと課題を解くにあたっての考え方について解説したいと思います.
第4回では,前回学んだif文,for文,while文の応用とその他の条件処理,ループ処理の方法を学びました.

if文
if文は,ある条件を満たす(あるいは満たさない)時にのみ何か処理をさせたい場合に使用するものです.

if(条件式){
            処理文
}

前回はここまで学びましたね.
では,ある条件の中にさらに条件がある,例えば「変数xが4と5の公倍数であり,変数y未満の場合」のような場合には,if文の処理文の中でさらにif文を入れ子にする(プログラミングにおいて,ネストにすると表現する)ことができます.上記の例をもとにすると,

if(x%4==0 || x%5==0){
             if(x < y){
                     処理文
}

のような書き方になります.
また,if文とelse文を組み合わせることで,さらに複雑な条件分岐もすっきりと書くことが可能になります.

if(条件式1){
           処理文1
}else if(条件式2){
           処理文2
}...
}else{
           処理文n
}

for文
for文はループ(繰り返し計算)処理を行う際によく用いられるものです.基本的な構文は,

for(初期設定部; 条件判定部; インクリメント部)  処理文

であるが,各部を"( )"の外で定義することも可能です.

int i = 0;  //初期設定部
for(  ;  ;  ){
           if(i > 10){  //条件判定部
                     処理式
           }
           i++;  //インクリメント部
}

ただし,このような書き方は書いていて混乱しやすいため,特別な場合を除き基本的な書き方に則って書くべきです.
for文もif文と同様,ネストにすることが可能です.

for(int i=0; i<10; i++){
    for(int j=0; j<10; j++){
         printf("%d × %d = %d\n", i, j, i*j);
    }
}

while文

while(条件式){
                 処理文
}

while文は条件式が真である間,処理が繰り返されます.ということは,条件式が最初から偽である場合,処理は一度も実行されません.
しかし,まず最初に一度処理をさせてから条件判定をしたい場合というのも出てくると思います.その時には,do-while文を使います.

do{
                 処理文  //最初から条件式が偽でも一度は実行される
}while(条件式)

すなわち,
・まず条件判定をさせたい → while文
・まず処理判定をさせたい → do-while文
といった使い分けとなります.



break文, continue文, switch文
ループの途中で終了判定を待たずにそのループから抜け出せるbreak文,ある条件の時は処理をさせないcontinue文というのもある.
そして,if-else文を多く用いらなければならなく,条件の評価対象が整数の場合,switch文というものを使うと,すっきり見やすく書けます.また,どちらもネストさせることが可能です.

switch(変数){  //変数は整数(int, char)のみ
    case 定数1:  //変数が定数1なら,処理文1が実行される
         処理文1;
         break;
    case 定数2:
         処理文2;
         break;
    default;         //どの条件にも当てはまらない場合(if-else文のelseに相当)
         処理文3;
         break;
}

どうでしょうか?if-else文より見やすくなりましたか?正直,これは条件分岐が多い場合を実際にプログラムした時に初めて恩恵を感じる気がします.このswitch文も先述のfor文,while文同様ネストさせる事ができます.

以上,かなりざっくりとしてますが第4回のおさらいになります.




では,課題の考え方について解説したいと思います.
5組
1.キーボードから整数を入力し,その数が7の倍数または17の倍数,かつ,1000以上2000未満に該当する数かどうかを表示せよ.

【実行例】
> 153R000000-04-1.exe
整数を入力:100
該当しません.

> 153R000000-04-1.exe
整数を入力:1190
該当します.

> 153R000000-04-1.exe
整数を入力:1309
該当します.

> 153R000000-04-1.exe
整数を入力:3192
該当しません.

この課題のポイントは,
 ①キーボードから整数を入力
 ②入力した整数が7の倍数または17の倍数
 ③1000以上2000未満
 ④②と③を同時に満たすかどうか
です.①は講義でもやったのでここでは省略します.②,③,④は四則演算子,論理演算子を利用することで表現できますが,順序を考慮しないと,目的の条件が得られないので注意が必要です.

2.キーボードから西暦を入力すると,その年が閏年かどうかを表示せよ.

【実行例】
> 153R000000-04-2.exe
何年?:2015
2015年は閏年ではありません.

> 153R000000-04-2.exe
何年?:2016
2016年は,閏年です.

> 153R000000-04-2.exe
何年?:2100
2100年は,閏年ではありません.

> 153R000000-04-2.exe
何年?:2000
2000年は,閏年です.

この課題のポイントは,
 ①入力した年が4で割り切れる
 ②①が真である年が100で割り切れ,400で割り切れない
です.つまり,まずは①の条件が真か偽かを判断し,真なら②の条件判定を行うことでこの課題は解けます.それぞれの処理は課題1同様四則演算と論理演算を用いれば解けます.

3.前の課題を参考にして,「西暦」と「何月」かを入力すると,その月は何日あるかを表示せよ.
月に1-12以外の数値が入力されたらエラーを返すこと. もちろん,閏年を考慮すること.

【実行例】
> 153R000000-04-3.exe
何年?:2016
何月?:20
入力エラー!

> 153R000000-04-3.exe
何年?:2016
何月?:5
2015年5月は,31日まであります.

> 153R000000-04-3.exe
何年?:2012
何月?:2
2012年2月は,29日まであります.

> 153R000000-04-3.exe
何年?:2000
何月?:2
2000年2月は,29日まであります.

> 153R000000-04-3.exe
何年?:1900
何月?:2
1600年2月は,28日まであります.

この課題のポイントは,
 ①入力された値が1~12以外の場合はエラーを返す
 ②閏年を考慮した条件分岐
です.どちらも条件分岐なので,if文とif-else文を組み合わせて処理を行うと良いでしょう.その後の入力された月の日にちは,授業内課題のQ4を少し改良すれば解けますね.

4.今日の最高気温を入力すると,「夏日」「真夏日」「猛暑日」「それ以外」のいずれかを画面に表示するプログラムを書きなさい. 用語の定義については,各自で気象庁のWebページを調べること.
ソースコード中にコメントとして情報元のWebサイトURLや書籍名をコメント/**/として記入すること.
この課題のポイントは,
 ①入力された数値が4つのうちのどの条件に属するかを判定する
です.これも四則演算と論理演算の組み合わせです.C言語において," /* "と" */ "の間の文字はコンパイル時にスルーされるので,メモなどはこの" /* */ "を用いて適宜コメントするのが良いでしょう.

5.じゃんけんの勝敗判定を行いたい.
グー=0,チョキ=1,パー=2として,A君とB君の2人の手を入力すると,勝敗またはあいこを判定して表示せよ.
入力エラー処理も行うこと.

【実行例】
> 153R000000-04-5.exe
A君(グー=0,チョキ=1,パー=2):4
入力エラー!

> 153R000000-04-5.exe
A君(グー=0,チョキ=1,パー=2):1
B君(グー=0,チョキ=1,パー=2):2
A君の勝ち

> 153R000000-04-5.exe
A君(グー=0,チョキ=1,パー=2):0
B君(グー=0,チョキ=1,パー=2):0
あいこ.

この課題のポイントは,
 ①入力された2つの数値が0~2以外の時はエラーを返す
 ②0~2の数値に対し,どの条件がA君の勝ち,B君の勝ち,あいこになるのか
です.①は課題3と同様でいいので省略します.②は,いくつか解決策があります.A君とB君の全ての場合を書く,A君の数値とB君の数値を大小比較する,などなど...
プログラムの書き方は一通りでないことの方が多いので,自分なりの考え方で解きましょう.


6組
1.for文を2回使用して以下に示すような九九の計算結果を表示するプログラムを作りなさい. このとき,桁をきちんと合わせて表示すること.

【実行例】
1   2   3   4   5   6   7   8   9 
2   4   6   8  10  12  14  16  18 
3   6   9  12  15  18  21  24  27 
4   8  12  16  20  24  28  32  36 
5  10  15  20  25  30  35  40  45 
6  12  18  24  30  36  42  48  54 
7  14  21  28  35  42  49  56  63 
8  16  24  32  40  48  56  64  72 
9  18  27  36  45  54  63  72  81 

この課題のポイントは,
 ①for文を2回使うこと
 ②桁を合わせること
です.①については...このページにヒントが載っていますね!
②については,画面に出力するprintfの中の変換指定(%dや%fなど)で桁数の設定ができますよね.
こういう分からない時こそ,Google先生に聞きましょう!「C言語 桁数揃え」などと検索すると...?

2.while文を用い (0<=x<=2π) の範囲で,f(x)=sin(x) の極小値fmin(a)とその位置 a を探索し求めよ. なお探索時のxの刻み幅 dx=0.0001 とする.
この課題のポイントは,
 ①while文の条件式
 ②三角関数を使う
 ③極小値を調べる
です.①は,何と何を比較して真偽を判定するのでしょうか?この問題文の中で,範囲が指定されている変数がありますよね!
②は,実は皆さんは習っていない部分があります.現段階ではまだ"おまじない"と教わったかもしれませんが,プログラムのコードの最初に"#include "というのを書いていますよね?この1行をコメントアウト(/*と*/で挟む)して保存・コンパイルしてみてください.printfやscanfに関するエラーが出てくると思います.今まで使っていたprintfやscanfは「標準入出力関数」と呼ばれるもので,これらを使用するためには,stdio.hというヘッダファイルをインクルードしなければいけないのです.難しい説明になってしまいましたが,"#include を最初に書いておくことでprintfやscanfが使えるようになる!"とだけ理解しておけば今は大丈夫です.同じように,sinやcos(これらを数学関数と言う)を使えるようにするためには,math.hをインクルードしなければなりません.具体的には,"#include "の下の行に"#include "と書けば,三角関数を使えるようになります.
③は,始めに極小値を代入する変数fminを用意しておき,インクリメントする前の変数のf'(x)と後の変数のf(x)の値を大小比較して,もしインクリメント後のf(x)の方が小さければ,極小値fminにf(x)を代入していく,というのを繰り返せば,最終的なfminが極小値となります.

3.何月かを入力するとその月の英語名(January等)を表示するプログラムをswitch文を用いて作れ.

【実行例】
今は何月ですか?:5 
ああ,今は May なんですね! 

この課題のポイントは,
 ①何がswitch文の変数になるのか
です.出力させたい月の英語名は,何から判断されますか?それを考えれば,何を変数にしたらいいのか分かると思います.

以上が,第4回の各クラスの課題を解くにあたっての考え方になります.
この回の最初にも書きましたが,命名規則を守って提出をしましょう

追記
学生の皆さん,この掲示板での質問を一番最初の記事のコメント欄に質問してますが,質問は最新の記事のコメント欄にお願いします.