プログラミング入門 第5回講義 制御の流れ(1) 第6回講義 ループ(その2) - for for文(3) break/continue(9) 見やすいプログラム(15) 効率の良い変数利用(20) マークのあるサンプルプログラムは /home/course/prog0/public_html/2013/lec/source/ 下に置いてありますから、各自自分のディレクトリに コピーして、コンパイル・実行してみてください Prog-0 2013 Lec06-1 Copyright (C) 1999 – 2013 by Programming-0 Group 再掲:ループの種類(p.132) 見張り方式 1 前回とりあげました ある特定の条件を満たしている間は、処理を 繰り返す(例:aが0より大きい間) 一般に繰り返し回数はあらかじめ 決まっていない カウンタ方式 2 今回とりあげます ループの回数を数える変数(カウンタ変数などと呼ぶ) を用いて繰り返し処理を決定する(例:10回) 一般的に繰り返し回数は固定 Prog-0 2013 Lec06-2 Copyright (C) 1999 – 2013 by Programming-0 Group for 文(カウンタ方式に良く使われる) (p.143) おもに カウンタ方式 のループに使用 whileに、初期化とカウンタ変数の更新を追加 3 for(初期化 ; 条件式 ; カウンタ変数更新){ 文; … } Prog-0 2013 Lec06-3 Copyright (C) 1999 – 2013 by Programming-0 Group サンプルプログラム #include <stdio.h> 1から10まで main() の和を求める { int i,total; i = 1; total = 0; while(i <= 10){ for(i = 1 ; i <= 10 ; i++){ total += i; total += i; i++; } (while版) } printf("1から10までの和は %d です\n",total); } 4 /home/course/prog0/public_html/2013/lec/source/lec06-1.c Prog-0 2013 Lec06-4 Copyright (C) 1999 – 2013 by Programming-0 Group for と whileの比較(p.144) for(初期化;条件式;カウンタ更新){ 文 … } 初期化 while(条件式){ 文 … 両者使い道は異なるが、 カウンタ更新 書き換えると、こうなる。 } 例 例 for(i = 0; i < 10; i++){ i = 0 sum += i; while(i < 10){ } sum += i; i++; } Prog-0 2013 Lec06-5 5 Copyright (C) 1999 – 2013 by Programming-0 Group カウンタ変数に関する注意 カウンタ変数には通常 整数型変数 を用いる 浮動小数点数では、等号条件(==)が成立しな いことがある(誤差を含むため) 例えば0.1は2進数では循 6 環小数になり、正確に表現 出来ない カウンタ変数には、整数型を用いる /home/course/prog0/public_html/2013/lec/source/lec06-2.c Prog-0 2013 Lec06-6 Copyright (C) 1999 – 2013 by Programming-0 Group いろいろなループ for(i = 0 ; i < 10 ; i++ ){ ..... } 基本形 i : 0,1,...9のループ for(i = 0 ; i <= 10 ; i += 27 ){ ..... } 等差数列 i : 0,2,4...10のループ for(i = 1 ; i <= 16 ; i *= 2 ){ ..... } 等比数列 i : 1,2,4,8,16のループ Prog-0 2013 Lec06-7 Copyright (C) 1999 – 2013 by Programming-0 Group ループの制御(p.142,151) ループ実行中に、break、continueを使用して ループの動作を変更する事が出来る ループ実行中に、ループの残りの全ての実行を取り やめる(ループからの脱出):break ループ実行中にその回の残りの実行を取りやめ、次 の回の実行に移る(ループの早送り): continue while/for以外のループとしてdo-whileが、 ループの制御としてその他にgotoがあるが、使用頻 度も少ないのでプログラミング入門では割愛する(自 習のこと) Prog-0 2013 Lec06-8 Copyright (C) 1999 – 2013 by Programming-0 Group break(p.146,152) ループ中にbreakがあると、 ループを脱出し、 ループの次の文に制御を移す。 case文の場合、caseからの 脱出に使用される。(第4回講 義参照) 二重ループなど、入れ子に なっているループの場合は、 一番内側のループからのみ脱 出する。 右例のように無限ループからの 脱出に良く使用される。 (第5回講義参照) while(..){ 8 Prog-0 2013 Lec06-9 break; } 次の文 while(1){ if(条件) break; } Copyright (C) 1999 – 2013 by Programming-0 Group continue(p.142) ループ中にcontinueがあると、 以降を実行せず、 条件判断の直前に制御を移す ループの外に脱出しない forの場合はカウンタ更新 を行い、再度条件判断 を行う while(..){ continue; 9 Prog-0 2013 Lec06-10 } Copyright (C) 1999 – 2013 by Programming-0 Group break/continueのプログラム例 #include <stdio.h> データを10個読み、正のデータのみの平均を計算 するプログラム main() { データの値が0ならループから抜け、 int i, data; それまで読んだデータと個数を用いて int num = 0, sum = 0; 平均を計算する for(i = 0 ; i < 10 ; i++){ scanf("%d",&data); データが負なら読み飛ばし、平均の計 算には使用しない(有効データ数にもカ if(data == 0) break; 10 ウントしない) if(data < 0) continue; 11 sum += data; 10個のデータのうち値が0より大きかっ num++; た「有効データ数」を表示 } printf("有効データ数 : %d\n",num); if(num != 0) printf("平均 } Prog-0 2013 Lec06-11 有効データ数が0で なければ平均を表示 : %f\n",(double)sum/num); /home/course/prog0/public_html/2013/lec/source/lec06-3.c Copyright (C) 1999 – 2013 by Programming-0 Group break/continueのプログラム実行例 std1dc1{s1000000}1: gcc lec06-5.c std1dc1{s1000000}2: ./a.out 1 2 3 4 5 6 7 8 9 10 11 12 有効データ数 : 10 平均 : 5.500000 std1dc1{s1000000}3: ./a.out 1 -2 3 4 -5 0 有効データ数 : 3 平均 : 2.666667 std1dc1{s1000000}4: Prog-0 2013 Lec06-12 1から10までの10個の データが使用される 1、3、4の3個のデータが 使用される Copyright (C) 1999 – 2013 by Programming-0 Group まとめ:while/forの使い分け whileとforは書き換え可 しかし、下記のように適材適所で使い分ける while文をつかう場面 見張り方式に良く使われる(Lec05-11) ループする回数が分からない、又は分かり辛い場合(「100以下の2のべき 乗の数2nの総和」など) 無限ループにも良く使われる 無限ループは while(1){..} と書く for文をつかう場面 カウンタ方式に良く使われる(Lec06-3) ループする回数が定数や決まっている場合(「1から10の合計」など) for文は初期化、条件、更新を1文で書けるので以下の長所がある Prog-0 2013 Lec06-13 コンパクトにまとめられる 初期化等の書き忘れがない Copyright (C) 1999 – 2013 by Programming-0 Group コラム:「難読Cプログラム国際コンテスト」? プログラミング入門の講義・演習では、一貫して「わかりやすいプログラム」を書くことを重 点にしています。しかし、世の中には、逆に「わかりにくいプログラム」を競うという、なん とも変わったコンテストがあります。それが、IOCCC (International Obfuscated C Code Contenst。日本語に訳せば「難読Cプログラム国際コンテスト」)です。このコンテストでは、 私たちの講義・演習とは逆に「いかにわかりにくく」「いかに読みにくく」「でもコンパイルは ちゃんと通って動く」というプログラムを作り、そのすごさを競うというものです。入賞作品、 そして優勝作品は、http://www.ioccc.orgでみることができます。 プログラムをみただけで頭が痛くなるようなものがたくさんありますが、中にはまるで芸術 作品のように「きれいな」(但し、見た目がです)ものもあったりします。例えば、こんなプロ グラム(1984年の「匿名希望」さんの作品)も、ちゃんとコンパイルでき、動作します。試し てみてはいかがでしょう? 但し、あまり深入りして解析しようとは思わない方がいいです よ。 int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);} Prog-0 2013 Lec06-14 Copyright (C) 1999 – 2013 by Programming-0 Group 見やすいソースプログラム 一見してプログラムの構造がわかるように、 空白 空行 インデント 12 などを利用して、ソースプログラムを整形する 整形せず、乱雑に書いたプログラムは、誤りが 混入しやすい Prog-0 2013 Lec06-15 Copyright (C) 1999 – 2013 by Programming-0 Group インデント(1) プログラム中で、if文や、for、while ループの中身 を、行頭に空白を入れて一段下げて記述すること つまり { } 下げる文字数は2~4文字ぐらいが適当 emacsのC-modeの場合 M-x indent-region(領域) か タブキー(1行) でインデントが出来る。 インデントが崩れているプログラムは「汚い!」と感じる 美意識を持とう 13 Prog-0 2013 Lec06-16 Copyright (C) 1999 – 2013 by Programming-0 Group インデント(2) インデントの方法には何通りかある。いろいろなプロ グラムを見て自分のスタイルを作ること 同じプログラムではインデントスタイルを 首尾一貫 させること。そうでないと余計見づらい。 以下はインデントの代表例である(他にもある) for(i = 0 ; i < 10 ; i++) { do_something(); } Prog-0 2013 Lec06-17 14 for(i = 0 ; i < 10 ; i++){ do_something(); } Copyright (C) 1999 – 2013 by Programming-0 Group インデント・空行の例 #include <stdio.h> main(){ int i; while(1){ printf("input number"); scanf("%d",&i); if(i<=0) break; if(i%2 == 0) printf("%dは偶数\n", i); else{ printf("%dは奇数\n", i); }} } Prog-0 2013 Lec06-18 #include <stdio.h> main() { int i; while(1) { printf("input number"); scanf("%d",&i); 意味の切れ目の 空行 if(i<=0) break; if(i%2 == 0) { printf("%dは偶数\n", i); } else { printf("%dは奇数\n", i); } } } Copyright (C) 1999 – 2013 by Programming-0 Group 実現方法の選択 #include <stdio.h> main() { int i, sum; /* 方法1 */ sum = 0; for(i = 1 ; i <= 10 ; i++){ sum += i; } 1から10までの和を5通りの方法で求める /* 方法2 */ sum = 0; i = 1; while(i <= 10){ sum += i; i++; } 5通りのループの計算結果は、 どれも同じである なるべく理解しやすい表現を選 ぶことが大事(特に、初心者のう ちは) 1から10までの和を求めるルー プの他の書き方を考えてみよう それぞれ変数 sumに1から10 までの和が計算 される /* 方法3 */ sum = 0; for(i = 1 ; i <= 10 ; sum += i++); /* 方法4 */ sum = 0; for(i = 0 ; i < 10 ;){ sum += ++i; } /* 方法5 */ sum = 0; i = 0; while(i < 10){ sum += ++i ; } } Prog-0 2013 Lec06-19 Copyright (C) 1999 – 2013 by Programming-0 Group コラム:計算量のオーダー 一般にn個のデータを処理するプログラムにおいて、計算する量が何に比例するかを表すものを 「計算量のオーダー」と呼び、「O()」で表す。これは「ランダウのO-記法」と呼ばれるが、単に「オー ダー」とも言われる。例えば計算量がn2に比例する場合はO(n2)と書く。 ここで1+2+3+…+nと言う計算を考える。 普通にループで計算するとすると、加算の回数はn-1回。これはO(n) となる。 等比数列の和の公式 n(n+1)/2 を使うとnに関わらず演算の回数は3回。 これは、nに関係しないので、O(1)と書く。 nをどんどん大きくすると両者の計算量はどんどん開いていく。 次にn個の要素の配列の大きさ順の並び替え(ソートと呼ぶ)を考える 一番簡単なのは、まず最大の要素を見つけ、次に2位の要素を見つける 作業を順に行うもので、比較の回数は(n-1)+(n-2)+...+1 でO(n2) 高速であるQuick sortだと、説明は省くが、O(n・log2n)となる。 グラフを見ると分るように、この場合もnが大きくなるとその差は大きくなる。 このように同じ作業(計算)を行う場合にも手順(アルゴリズム)によって 計算量は大きく変わる。 計算量が変わると言う事は、実行時間も変わって来ると言う事で、プログラミングコンテストなどで は実行時間に制限を設けたりする場合もある。 Prog-0 2013 Lec06-20 Copyright (C) 1999 – 2013 by Programming-0 Group
© Copyright 2024 ExpyDoc