Document

プログラミング入門
第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