プログラミング入門 第5回講義 制御の流れ(1) 第5回講義 ループ(その1) - while インデント(3) ループとは(7) フローチャート(8) ループの種類・while文(10) 代入演算子(14) インクリメント・デクリメント(15) 無限ループ(20) マークのあるサンプルプログラムは /home/course/prog0/public_html/2013/lec/source/ 下に置いてありますから、各自自分のディレクトリに コピーして、コンパイル・実行してみてください Prog-0 2013 Lec05-1 Copyright (C) 1999 - 2013 by Programming-0 Group 復習:if/switch-caseの使い分け switch-case文をつかう場面 変数の値による場合分けで、しかも場合が比較的多い時 (条件は等号でないといけない事に注意) いくつかの場合の処理が同じなら、breakなしのcaseが使える if文をつかう場面 条件が複雑な時(例えば、「条件AとBの真偽による4つの場合分け」には switch-caseを使用する事は非常に難しいだろう) 条件が等号でない場合(!=、<、<=、>、>=など) switch-caseが使える時でも、あまり場合分けが多くない(3個ぐらい)だとif-else を使用した方がコンパクトにまとめられる Prog-0 2013 Lec05-2 Copyright (C) 1999 - 2013 by Programming-0 Group インデント(段づけ)をしよう! インデント(段づけ)をすると 見やすく、間違いにくく なる 以下のスタイル1、2が標準的。 1 スタイル1(行数が少なく、コンパクトにまとまる) if (a == b){ printf("a,b were equal\n"); } スタイル2(カッコの対応が見易い) 自動的にインデントする方法は、 Lec06-15で説明します if (a == b) { printf("a,b were equal\n"); } Prog-0 2013 Lec05-3 Copyright (C) 1999 - 2013 by Programming-0 Group 複雑なif文に騙されるな(1) 以下は日付を入力して、それが月の最後の日かどうかを表示する プログラム。(ただし閏年と、あり得ない日付(5月40日など)には対応していない) #include <stdio.h> main() { int m,d; printf("月と日を空白で区切って入力してください : "); scanf("%d %d",&m, &d); みかけは正しそう だが、実際はうまく 動かない if((m == 1) || (m == 3) || (m == 5) || (m == 7) || (m == 8) || (m == 10) || (m == 12)) if(d == 31) printf(“%d月%d日は月の最後の日\n",m,d); else if((m == 4) || (m == 6) || (m == 9) || (m == 11)) if(d == 30) printf("%d月%d日は月の最後の日\n",m,d); else if(m == 2) if(d == 28) printf("%d月%d日は月の最後の日\n",m,d); else printf("%d月%d日は月の最後の日ではない\n",m,d); } Prog-0 2013 Lec05-4 Copyright (C) 1999 - 2013 by Programming-0 Group /home/course/prog0/public_html/2013/lec/source/lec05-1.c 複雑なif文に騙されるな(2) 前頁のプログラムをちゃんとインデント(if-elseの関係に注目して段づけする)して みると、以下のようになり、論理的におかしい事が分かる。 #include <stdio.h> main() { int m,d; printf("月と日を空白で区切って入力してください : "); scanf("%d %d",&m, &d); if((m == 1) || (m == 3) || (m == 5) || (m == 7) || (m == 8) || (m == 10) || (m == 12)) if(d == 31) printf("%d月%d日は月の最後の日\n",m,d); else if((m == 4) || (m == 6) || (m == 9) || (m == 11)) if(d == 30) printf("%d月%d日は月の最後の日\n",m,d); else if(m == 2) if(d == 28) printf("%d月%d日は月の最後の日\n",m,d); else printf(“%d月%d日は月の最後の日ではない\n",m,d); } Prog-0 2013 Lec05-5 /home/course/prog0/public_html/2013/lec/source/lec05-2.c Copyright (C) 1999 - 2013 by Programming-0 Group 複雑なif文に騙されるな(3) これが正しいプログラム(インデントも正しくされている) #include <stdio.h> main() { int m,d; printf("月と日を空白で区切って入力してください : "); scanf("%d %d",&m, &d); if(((m == 1) || (m == 3) || (m == 5) || (m == 7) || (m == 8) || (m == 10) || (m == 12))&&(d == 31)) printf("%d月%d日は月の最後の日\n",m,d); else if(((m == 4) || (m == 6) || (m == 9) || (m == 11))&&(d == 30)) printf("%d月%d日は月の最後の日\n",m,d); else if((m == 2)&&(d == 28)) printf("%d月%d日は月の最後の日\n",m,d); else printf("%d月%d日は月の最後の日ではない\n",m,d); lec05-3c.cは } 更に閏年にも 対応した Prog-0 2013 Lec05-6 Copyright (C) 1999 - 2013 by Programming-0 Group /home/course/prog0/public_html/2013/lec/source/lec05-3{a,b,c}.c 繰り返し(ループ)とは何か(p.132) ある条件が成立している間、 同じ処理を何度も繰り返すこと 2 お金がある限り宝くじを買う グラウンドを20周する Cの繰り返しの命令(文) while, for, (do-while) Prog-0 2013 Lec05-7 Copyright (C) 1999 - 2013 by Programming-0 Group フローチャート(p.60) 前回既に登場 下のような図形を有向線でつないで処理 の手順(アルゴリズム)を表す ループ開始 ループ終了 キー入力 条件分岐 処理 起点・終点 真 真の場合 の処理 偽 偽の場合 の処理 入出力 分岐 画面出力 Prog-0 2013 Lec05-8 Copyright (C) 1999 - 2013 by Programming-0 Group 繰り返しのフローチャート 図的表現例 九九の七の段の計算 yに7を代入 繰り返し: xを1から9まで1ずつ増加 zにx*yの計算結果を代入 zの値を表示 繰り返しここまで Prog-0 2013 Lec05-9 フローチャート xを1から9まで1 ずつ増加 z=x*y; zを表示 Copyright (C) 1999 - 2013 by Programming-0 Group ループの種類(p.132) 見張り方式(while) 今回とりあげます ある特定の条件を満たしている間は、処理を 繰り返す(例:aが0より大きい間) 一般に繰り返し回数は あらかじめ決まっていない 3 カウンタ方式(for) 次回とりあげます ループの回数を数える変数(カウンタ変数などと呼ぶ) を用いて繰り返し処理を決定する(例:10回) 一般的に繰り返し回数は 固定 4 Prog-0 2013 Lec05-10 Copyright (C) 1999 - 2013 by Programming-0 Group while 文(見張り方式に良く使われる) (p.132) 条件式が真の間はループの中身を実行し続け、 条件式が偽になれば終了(ループの次の文を 実行)する while(条件式){ 文; ... } Prog-0 2013 Lec05-11 Copyright (C) 1999 - 2013 by Programming-0 Group ループのサンプルプログラム A B 1+2+3....と順に加えていっ #include <stdio.h> て、初めて和が25を超える数と、 main() その時の和を求める { int i,total; std1dc1{s1000000}1: gcc lec05-7.c i = 0; std1dc1{s1000000}2: ./a.out total = 0; 数は 7 で、和は 28 です while( total <= 25 ){ std1dc1{s1000000}3: i = i + 1; total = total + i; } printf("数は %d で、和は %d です\n", i, total); } 5 /home/course/prog0/public_html/2013/lec/source/lec05-4.c Prog-0 2013 Lec05-12 Copyright (C) 1999 - 2013 by Programming-0 Group 実行経過 値 ループ 1回目 2回目 3回目 4回目 5回目 6回目 7回目 8回目 Prog-0 2013 Lec05-13 A地点 B地点 i total i total 0 0 1 1 1 1 2 3 2 3 3 6 3 6 4 10 4 10 5 15 5 15 6 21 6 21 7 28 ループから脱出(ループは7回まわった) 6 7 Copyright (C) 1999 - 2013 by Programming-0 Group 代入演算子について(p.87) =以外に, +=, -=, *=, /=, %=がある x x x x x Prog-0 2013 Lec05-14 += -= *= /= %= y y y y y ⇒ ⇒ ⇒ ⇒ ⇒ x x x x x = = = = = x x x x x + * / % y y y y y Copyright (C) 1999 - 2013 by Programming-0 Group インクリメント・デクリメント演算子 (p.135) ループの中で、カウンタ変数を使う例が多い。 繰り返し回数の把握、回数に応じた制御。 変数に1を加える操作 i++, ++i インクリメント 変数から1減じる操作 デクリメント i--, --i 符号の位置が、前(前置)と後(後置)で 意味が違う → 次ページ Prog-0 2013 Lec05-15 Copyright (C) 1999 - 2013 by Programming-0 Group 前置と後置の違い(p.136) 前置(++i、--i) i = i + 1; ⇒ iに1加え(減じ)てから、 値を返す j = i; 後置(i++、i--) と同じ ⇒iの元の値を返してから、1加える(減じる) 8 9 前置 後置 例:i=6の時、実行後の値は j = ++i; ⇒ i:7 , j:7 j = i++; ⇒ i:7 , j:6 j = i; i = i + 1; と同じ 単独で使用する場合は前置でも後置でも同じ 前置 後置 Prog-0 2013 Lec05-16 例:i=6の時、実行後の値は ++i; ⇒ i:7 i++; ⇒ i:7 Copyright (C) 1999 - 2013 by Programming-0 Group インクリメント・デクリメント 前置と後置の違い #include <stdio.h> main() { int i, j; 2つの整数i, jは 最初0に初期化 i = 0; j = 0; while( i < 5 ) { 前置の値をjに代入 j = ++i; printf( "前置: i は %d, j は %d です\n", i, j ); } i = 0; j = 0; } 今度は後置の値をjに代入。 while( i < 5 ) { j = i++; printf( "後置: i は %d, j は %d です\n", i, j ); } Prog-0 2013 Lec05-17 /home/course/prog0/public_html/2013/lec/source/lec05-5.c Copyright (C) 1999 - 2013 by Programming-0 Group 前のプログラムの出力結果 一見似たようなループなのだ が、左にあるように出力結果 が異なる。 前置: 前置: 前置: iの値は同じように出ているが、 前置: jの値の出力が、前置と後置で 前置: 異なることに注意。 後置: 前置では、まず1加算してからj 後置: に代入しているのに対し、後置 後置: では代入後、1加算する操作を 後置: している。この違いが出ている。 後置: 前置・後置を組み合わせて 使う場合、この点に注意する。 Prog-0 2013 Lec05-18 i i i i i i i i i i は は は は は は は は は は 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, j j j j j j j j j j は は は は は は は は は は 1 2 3 4 5 0 1 2 3 4 です です です です です です です です です です Copyright (C) 1999 - 2013 by Programming-0 Group インクリメント演算子・代入演算子の使用例 #include <stdio.h> main() Lec05-12のプログラム { lec05-4.cを書き換えた int i,total; i = 0; total = 0; while( total <= 25 ){ i++; この場合は前置でも後置でも構わない total += i; } printf("数は %d で、和は %d です\n", i, total); } /home/course/prog0/public_html/2013/lec/source/lec05-6.c Prog-0 2013 Lec05-19 Copyright (C) 1999 - 2013 by Programming-0 Group whileを使った無限ループ while(1)で制御される構造は、 条件式が常に真(1)なので無限ループである。 ある条件を満たした時にループを脱出するよう、 if文でbreakを入れる使い方がある。 10 (入力制限・エラー処理などを、while(1){ … }でくくる) while( 1 ){ printf("\n0から100までの整数を入力しなさい\n"); scanf("%d", &a); breakについて 第3回講義で出て来た if (a >= 0 && a <= 100) break; caseからの脱出と同様、ループからの } 脱出にも使われる 詳しい説明は次回(第6回)講義で行う Prog-0 2013 Lec05-20 Copyright (C) 1999 - 2013 by Programming-0 Group 無限ループの例(Lec05-12を改変) #include <stdio.h> 和が25を越えたら無限 main() ループを脱出する。 { 元は「和が25以下だったらル ープ 『継続』 」という条件だ 無限ループ int i,total; ったので, i = 0; while(total <= 25) total = 0; としていた。 while(1){ 今度は『終了』条件なので条 件式が逆になっている。 if (total > 25) break; i = i + 1; total = total + i; } printf("数は %d で、和は %d です\n", i, total); } 11 /home/course/prog0/public_html/2013/lec/source/lec05-7.c Prog-0 2013 Lec05-21 Copyright (C) 1999 - 2013 by Programming-0 Group ループとifの組み合わせ例 ある地点から別の地点へ徒歩で行く場合 の所要時間を考えるプログラム 途中に信号が5カ所あるとする std1dc1{s1000000}1: ./a.out 信号間の所要時間は3分 信号が赤だったら信号待ちでさらに1分 (計4分) 1番目の信号は(青:0, 2番目の信号は(青:0, 3番目の信号は(青:0, 信号が青か赤かを入力して、所要時間を 4番目の信号は(青:0, 5番目の信号は(青:0, 積算する 所要時間は17分でした 赤:1)?:0 赤:1)?:0 赤:1)?:1 赤:1)?:1 赤:1)?:0 最後に積算結果を表示する 右の実行例では、青が3回、赤が2回 所要時間は3+3+4+4+3=17分 Prog-0 2013 Lec05-22 Copyright (C) 1999 - 2013 by Programming-0 Group ループとifを使用したサンプルプログラム #include <stdio.h> main () { int i = 1; int signal; int time = 0; 信号の回数(カウンタ) 信号の状態 所要時間 の3つが必要な変数 信号の回数を監視 while (i <= 5) { printf("%d番目の信号は(青:0, 赤:1)?:", i); scanf("%d", &signal); 信号の状態に応じて所 if (signal == 0) time += 123; 要時間を加算(代入演 else time += 4; 算子を使っている) i++; 信号の回数を加算 } printf("所要時間は%d分でした\n", time); } /home/course/prog0/public_html/2013/lec/source/lec05-8.c Prog-0 2013 Lec05-23 Copyright (C) 1999 - 2013 by Programming-0 Group ループとswitch-caseの組み合わせ例 i = 1; while (i <= 5) { printf("%d番目の信号は(青:0, 赤:1, 点滅:2)?: ", i); scanf("%d", &signal); switch (signal) { 点滅していたら急ぎ case 0: 足になるので2分で time += 3; 行けるとする break; 実行例 危ないので実際に case 1: std1dc1{s1000000}1: ./a.out は走らないこと time += 4; 1番目の信号は(青:0, 赤:1, 点滅:2)?:0 3通りになるので break; 2番目の信号は(青:0, 赤:1, 点滅:2)?:0 case 2: switch-caseを 3番目の信号は(青:0, 赤:1, 点滅:2)?:2 time += 2; 4番目の信号は(青:0, 赤:1, 点滅:2)?:1 用いる break; 5番目の信号は(青:0, 赤:1, 点滅:2)?:0 前ページプログラ } 所要時間は15分でした i++; ムのwhileの中だ } け右に示す /home/course/prog0/public_html/2013/lec/source/lec05-9.c 先の例に信号が点 滅していた場合を 追加 Prog-0 2013 Lec05-24 Copyright (C) 1999 - 2013 by Programming-0 Group
© Copyright 2024 ExpyDoc