情報処理Ⅱ 第3回 2007年10月22日(月)
本日学ぶこと 制御文 問題 入れ子,多重ループ switch~case 九九の表を出力できる? 1st, 2nd, 3rd, 4th, …, 1000th と順番に序数を生成 できる?
多重ループの準備 大小のサイコロ1個ずつを振ったときの出目は何種類? (大,小)=(1,1),(1,2),…(6,6)の36種類.しかし全てを数え上げるのは手間がかかるし,間違いも起こりやすい. 大の出目は1~6のいずれか.そのそれぞれに対して,小の出目は1~6のいずれか.したがって6×6=36種類.
九九プログラム 方針 1≦i≦9, 1≦j≦9の各(i,j)について,i * jを計算する. 1≦j≦9のそれぞれのjの値に対して, 1≦i≦9のそれぞれのiの値との積を計算し,出力する for (j = 1; j <= 9; j++) { for (i = 1; i <= 9; i++) { printf("%2d ", i * j); } printf("\n"); 上の例では,「forの二重ループ」とも言う. 三重,四重,…と増やすこともできる. for文の中にfor文… for文の「入れ子 (ネスト)」という kuku.c 入p.97 i=3, j=9 リp.252
ループの用語 ループ(loop):反復のこと ループカウンタ:反復処理を制御する変数のこと.for文の中で使われる. 「forループ」,「whileループ」などという. ループカウンタ:反復処理を制御する変数のこと.for文の中で使われる. 2重ループ:ループの中にループを書くこと 多重ループ:2重ループ,3重ループ,4重ループ…の総称
多分岐(1) 構文 if (条件1) { たまに使う if文の中にif文… if 文の「入れ子」 リp.239 if (条件2) { 条件1~2をともに満たすときの処理 } else { 条件1を満たすが,条件2を満たさないときの処理 } 条件1を満たさないときの処理 if文の中にif文… if 文の「入れ子」 リp.239
多分岐(2) 構文(else if文) if (条件1) { よく使う リp.237 条件1を満たすときの処理 条件1を満たすときの処理 } else if (条件2){ 条件1は満たさず,条件2を満たすときの処理 } else if (条件3) { 条件1~2は満たさず,条件を3を満たすときの処理 } else { 条件1~3のいずれも満たさないときの処理 } リp.237
AND条件とOR条件 AND条件 OR条件 if (条件1 && 条件2) { if (条件1 || 条件2) { よく使う 条件1~2をともに満たすときの処理 } else { 条件1~2の少なくとも一方を満たさないときの処理 } OR条件 if (条件1 || 条件2) { 条件1~2の少なくとも一方を満たすときの処理 条件1~2をともに満たさないときの処理 「パイプ記号」(Shiftを押し ながら「\」)を2個 「|」の呼称:パイプ,縦棒,pipe,vertical bar 入p.215 リp.161
序数プログラム 方針 1≦number≦1000の各整数に対して(for文を用いて), その序数となる英単語を出力する 出力方法 printf("%dst", 1); ⇒ 1st printf("%dnd", 2); ⇒ 2nd printf("%drd", 3); ⇒ 3rd printf("%dth", 4); ⇒ 4th
序数プログラム 方針(つづき) 接尾辞のつけかた 下2桁が「11」,「12」もしくは「13」のとき,"th" 下1桁が「1」のとき,"st" 下1桁が「2」のとき,"nd" 下1桁が「3」のとき,"rd" それ以外は,"th" 下?桁 整数iの下1桁 ⇒ iを10で割った余り ⇒ i % 10 整数iの下2桁 ⇒ iを100で割った余り ⇒ i % 100 ordinal.c
switch~case 多分岐を実現するもう一つの方法 構文 switch (整数値) { たまに使う コロン … 値1の処理 break; case 値2: 値2の処理 … default: それ以外の処理 } 整数値 値1の処理 値2の処理 それ以外 の処理 break … コロン リp.240, p.242
switch~caseにbreakが なかったら 滅多に使わない 構文 switch (整数値) { case 値1: 値1の処理 case 値2: 値2の処理 … default: それ以外の処理 } 整数値 値1の処理 値2の処理 それ以外 の処理 … リp.244
序数プログラムを書き換える ifをswitch~caseに置き換える ordinal2.c
制御文に関する補足 ブロック breakとcontinue 無限ループ whileとforの使い分け
ブロック 「{ 処理 }」をブロック(複合文)という 「処理」には複数の文が書ける. セミコロンまでが一つの文. 制御文を用いた if (…) {…} なども(セミコロンはなくても)一つの文. ブロックの先頭で,変数を宣言できる.この変数は,ブロックが終わると利用できなくなる. リp.222
{ と } が省略可能なとき 「処理」が一つの文のときは,{ と } を省略できる. if (条件) 処理 ただし,条件を満たすときにする処理,満たさないときにする処理が紛らわしくなるので,常に { と } をつけるようにしておくとよい if (条件) 処理1; 処理2; if (条件) { 処理1; 処理2; } if (条件1) if (条件2) 処理1; else 処理2; if (条件1) { if (条件2) 処理1; } else 処理2; 「処理が一つの文のときは,{ と } を省略できる」の代わりに 「処理は一つの文でなければならない.ここで,文とは,単文,複合文(ブロック),if文,for文,while文,…,である」 と表現することもできる.(リp.215も参照のこと) 条件の真偽にかかわらず 処理2を実行する. 違う! 条件1が真,条件2が偽のとき に限り,処理2を実行する. 違う!
breakとcontinue break continue 注意点 for, while, do, switchの処理の中で使用でき,それぞれのブロックから脱出する. continue for, while, doの処理の中で使用でき,反復の先頭に戻る. forでは,増分してから条件判定へ while, doでは,ただちに条件判定へ 注意点 ifやelseのブロックでbreakをすると,そのブロックではなく,より外側の(forなどの)ブロックから脱出する 入れ子の中から一気に脱出はできない(gotoが必要) リp.263, p.265
無限ループ 例 注意点 while (1) { for (;;) { たまに使う 例 while (1) { 処理 } for (;;) { 注意点 通常は,「処理」の中にif文を設け,何らかの条件でbreakによって抜けるように書く. 条件 (恒真) 処理 リp.254
whileとfor while文をfor文で記述可能 for文をwhile文で記述可能 使い分けは? 条件 処理 初期化 条件 処理 増分 空文 (くうぶん) リp.251
制御文:まとめ 「反復」は,for, while, do~while 「分岐」は,if, switch~case 制御文は入れ子にできる.「{」と「}」の対応に注目して読む breakはブロックを抜け,continueは反復の先頭に戻る.適用される制御文に注意
次に学ぶこと 演算子(Operator) +, -, =, %, ++ ,&& ,||, == など C言語ではどんな演算子が使用できるか? 演算子間の優先順位はどうなっているか? 例: 2 + 3 * 4 と書けば,(2 + 3) * 4 ではなく 2 + (3 * 4) と解釈される.このとき,* は + よりも 優先順位が高いという.
用語説明 演算対象をオペランド(operand)という. 代入できるオブジェクトを左辺値(lvalue)という. y = x + 1; のとき, x と 1 は,演算子 + のオペランド y と x + 1 は,演算子 = のオペランド 代入できるオブジェクトを左辺値(lvalue)という. 例: p = (++q) + 1; としたときの p と q 演算子を適用して値を得ることを評価という. 例: if (x = 3) {...} のとき,「x = 3」により,xに3が代入されるとともに,この式を評価した値は3となる. 「left value」の略 オペランドは「被演算子」ともいう. 「左辺値」について,規格には「代入可能な左辺値」という概念もあるが,煩雑なので, 多くのプログラミング言語で使用されている用法を採用した. 入p.194では「被演算数」と呼んでいるが,これは対象を狭く見ている.例えば, 「100 ÷ 2 + 5 × 4 - 25」という式に対して,演算子+のオペランドは, 「100 ÷ 2」と「5 × 4」とするのが自然である. 入p.194 リp.149
2項演算子 加減算演算子: +, - 乗除演算子(1): *, / 乗除演算子(2): % (剰余を求める.オペランドは整数) アスタリスク 加減算演算子: +, - 乗除演算子(1): *, / 乗除演算子(2): % (剰余を求める.オペランドは整数) 関係演算子: <, >, <=, >=, ==, != 暗黙の型変換が起こる場合を除き,2つのオペランドは同一の型でなければならない. ○ if (2 == 3.14) … × if ('a' == "abc") … ○ if (0x61 == 'a') … ○ if ("abc" == "bcd") … スラッシュ 等しいか比較する ときは,= ではなく == if (2 == 3.14)では,暗黙の型変換により2がdouble型になる. if (0x61 == 'a')は,比較の両辺ともint型である. if ("abc" == "bcd")では,"abc"も"bcd"もchar *型(charのポインタ型)になる.ただしこれは常に偽である. 文字列の内容が等しいか判定するには,==ではなく,ライブラリ関数のstrcmpを用いるとよい. 入p.207, p.213 リp.159, p.160
代入演算子 =, +=, -=, *=, /=, %= など 左側のオペランドは左辺値でなければならない. x 記号= y; は,x = x 記号 y; と同じ. 左側のオペランドは左辺値でなければならない. x + 1 = y; はNG. 右から左に結合する.左辺値に格納される値を演算結果とする. x += y = z + 2; ⇒ y = z + 2; x += y; と同じ 入p.211 リp.163
論理演算子 AND: && (2項演算子) OR: || (2項演算子) NOT: ! (単項演算子) 優先順位は ! > && > || 真偽とCでの表現 真: 0以外に評価される値 偽: 0に評価される値 例: 1 && 2は真(具体的には,1)である. && の左を偽と評価すれば,右は評価しない. || の左を真と評価すれば,右は評価しない. int a[10]; … if (x >= 0 && x < 10 && a[x] == y) とすると,x<0 や x≧10のときは a[x] == y を評価しない. 入p.215 リp.158, p.161
論理演算 偽:整数型なら0,浮動小数点型なら0.0,ポインタ型ならNULLと等しくなる値. x y x && y x || y x !x 真 真 1 1 真 偽 真 1 偽 1 真 偽 1 偽 偽 偽:整数型なら0,浮動小数点型なら0.0,ポインタ型ならNULLと等しくなる値. 真:偽でないスカラ型(整数型,浮動小数点型もしくはポインタ型)の値.
演算子:ここまでのまとめ Cでは多彩な演算子が利用できる.いくつかは数学の記号に近く,いくつかはC独特である.