C基礎4 繰返し処理
C基礎4 繰返し処理
繰返すプログラムを勉強します。繰返す制御文の文法や作法の説明もしますが、本章では、繰返しの一番基本的なアルゴリズムである「N回繰返す」書き方を紹介しています。
プログラムは様々な書き方ができてしまいます。結果は同じでも、その書き方は千差万別で、プログラムを作る時に、毎回悩んでしまいます。そこで、よくある処理の塊については、一定の書き方(アルゴリズム)を使う様にしています。
「N回繰返す」アルゴリズムの他、幾つかのアルゴリズムを紹介します。
動画は、Windows10とVisualStudio2019を使った説明になっていますが、WIndows11とVisualStudio2022を使った場合の操作方法と同じです。
プログラムの基本構造には、以下の3つの構造があります。
順次構造
選択構造
繰返し構造
while文、do-while文、for文は、この繰返し構造を作る文です。
繰返す回数をカウントする変数を、カウンタ変数若しくは単にカウンタと呼びます。カウンタは、1,2,3、・・・という様に、1つずつカウントアップしていく事が多くあります。また、5,4,3,・・・という様に、1つずつカウントアップしていくこともあります。1ずつカウントアップしたり、カウントダウンしたりするのに便利なインクリメント演算子(++演算子)やデクリメント演算子(--演算子)があります。便利な演算子ですので、積極的に使うとよいでしょう。
繰返し構造になってくると、プログラムのロジックが段々複雑化してきます。プログラムは様々な書き方が出来てしまいますので、よく出てくるロジックは、定型的な書き方にすると、プログラミングが楽になります。ここでは「N回繰返す」というロジックの代表的な3つの書き方を説明します。
3つの繰返し文の文法と、作法に従った書き方を学びます。
文法や作法だけでなく、繰返し構造のプログラムの式や文が、コンピュータの中で、どの様に実行されていくのかを説明していますので、プログラムの流れもイメージできる様にしましょう。
・繰返し条件が、真の間繰返す
3つの繰返しの為の制御文がありますが、繰返し条件は、真の間繰返します。
・繰返し条件は前判定型と後判定型の2つがある
while文とfor文は前判定型、do-while文が後判定型です。
・while文の文法は「while(式) 文」
作法としては、if文の時と同じ様に、繰返される文は、{ } を使って、ブロック化します。
・do-while文の文法は「do 文 while(式);」
作法としては、if文の時と同じ様に、繰返される文は、{ } を使って、ブロック化します。
do-while文は、繰返し条件が下に書かれるため、繰返し処理が長くなると、どういう条件で繰返しているのかが分かり難くなります。while文でもdo-while文でも、どちらでも書く事ができるプログラムの場合は、while文で書くようにしましょう。
・for文の文法は「for(式1;式2;式3) 文」
作法としては、if文の時と同じ様に、繰返される文は、{ } を使って、ブロック化します。
3つの繰返し文の中で、一番よく使われるのがfor文です。
・1足すのが++演算子、1引くのが--演算子
後置型と前置型がありますが、詳しくは「4.2 インクリメントとデクリメント演算子の前置と後置の違い」で説明します。for文の式3の所で、よく使われる演算子です。
・「N回繰返す」for文の3つの書き方を覚える
1からスタートカウントアップ方式、0からスタートカウントアップ方式、Nからスタートカウントダウン方式の3つの書き方を覚えましょう。
FizzBuzz問題は、英語圏の有名な言葉遊びである「Fizz Buzz」をプログラムにする、という問題で、コードが書けないプログラマ志願者を見分ける手法として提案された問題でもあります。
1から100までの数を順に表示しますが、3や5の倍数の場合は数を表示せずに、3の倍数なら「Fizz」、5の倍数なら「Buzz」、3と5の公倍数なら「Fizz Buzz」と表示するプログラムを作成しましょう。
なお、表示は20行以内に収まる様に工夫しましょう。
++演算子と--演算子は単項演算子で、変数名の前や後ろに書く事ができます。++演算子と--演算子は、計算式や定数に使う事はできず、変数にしか使うことができません(代入演算子の左辺と同じ)。
変数名の前に書く事を前置、変数名の後ろに書く事を後置と言います。
前置は±した後の値が式の結果になり、後置は±する前の値が式の結果になります。
前置と後置の違いを、プログラムの動きを追いながら説明しています。
複雑な使い方ではなく、先ずは単純な使い方が出来る様になりましょう。
・前置は「±1した後」が式の値になる
「y = ++x;」や「y = --x;」のように、++や--を、変数の前に書くと、+1や-1した後の結果が、式の結果になります。
この例のプログラムでは、変数xの変化後の値が変数yに代入され、変数xと変数yの値は同じになります。
・後置は「±1する前」が式の値になる
「y = x++;」や「y = x--;」のように、++や--を、変数の後ろに書くと、+1や-1する前の値が、式の結果になります。
この例のプログラムでは、変数xの変化前の値が変数yに代入されますので、変数xと変数yの値は異なります。
・1つの式内で、代入行為を行った変数を参考/更新しない
++演算、--演算、複合代入を含む代入演算を行い、値が変化する変数を、1つの式内で参照したり、別の代入を行ってはいけません。1つの式の中で行う代入行為は、1つだけにしましょう。複雑な式にしないのが無難です。
・++と--演算はfor文の式3と単独式文で使い慣れる
++演算子と--演算子は、前置と後置で、結果が異なる場合があります。最初は、前置でも後置でも結果が同じになる、for文の式3の所と、単独式文で使い慣れると良いでしょう。
break文とcontinue文は、繰返しの中で使うことのできる制御文です。break文は、switch文の時に使いましたが、繰返し文による繰返しの中で使うこともできます。
break文とcontinue文は、プログラムの流れを変えるもので、フローチャートでは、繰返しを抜けたり、繰返しを継続させる線で表わされます。自由な場所に流れを変えることができるものではなく、決められた場所に流れが変わります。フローチャートで、その位置を確認するようにしましょう。
最初に、3つの繰返し文の文法と、フローチャートで、そのプログラムの流れを復習します。
break文とcontinue文を学びます。
これらの制御文を使うと、プログラムの流れが、どこに変わるかを、フローチャートとプログラムを使って説明しています。
・break文は繰返しを抜ける
break文は、繰返し文(while, do-while, for)の中に書く事もできます。
繰返し文として、直接書くのではなく、繰返しの中にあるif文またはelse文の中に書きます。
switch文の中にbreak文を書くと、switch文を抜ける動作だけで、繰返し文を抜ける抗力はなくなります。
・continue文は繰返しを継続する
continue文は、繰返し文(while, do-while, for)の中でのみ、書く事ができます。
繰返し文として、直接書くのではなく、繰返しの中にある、if文またはelse文またはswitch文の中に書きます。
・無限ループを書けるようにする
繰返し条件に、常に真となる式を書く事で、無限ループを作る事ができます(for文は式2の省略が無限ループ)。
代表的な3つの書き方を紹介しています。
rewind関数は、確実にキー入力待ちの状態を作るために必要な関数です。scanf関数でキー入力する時、内部的に用意されたバッファと呼ばれる入れ物に、入力したキーが溜められます。このため、確実にキー入力状態にするためには、rewind関数を使って、バッファを空にする必要があります。
getchar関数は1文字をキー入力する関数で、putchar関数は1文字を画面に表示する関数です。scanf関数とprintf関数で「%c」という書式指定子を書く事でプログラムできますが、getchar関数とputchar関数を使うことで、プログラミングが楽になります。その例として「EOF入力するまで繰返す」というプログラムがあります。EOFというのは、End Of Fileの略で、ファイルの終わりを意味するものです。Windowsのコマンドプロンプト画面では、特別なキー操作(Ctrl+Z)で、EOFを入力することができ、getchar関数は、これを通知してくれます。ここでは、このよく登場する「EOF入力するまで繰返す」というプログラムの書き方を説明します。
文字のキー入力と画面表示を復習する中で、rewind関数の動きを説明しています。確実にキー入力待ちの状態にしたい場合は、scanf関数やgetchar関数の前に、rewind関数を呼び出す必要があります。
1文字入力をEOFが入力されるまで繰返す、という代表的なプログラムの書き方についても学びます。
・rewindは溜まったキー入力を捨てる
scanf関数やgetchar関数でキー入力すると、キー入力係は、Enterキーが押されるまでのキーをバッファに溜め込みます。新たにキー入力したい場合は、溜め込んでいたキーを捨てる必要があります。この溜め込んだキーを捨てるのがrewind関数です。
・「溜まったキーを捨て文字入力する」がEnterキー待ちの状態を作る
今まで、Enterキー待ちの状態にしたい時に書いていた2行の意味は、溜め込んだキーを捨てることで、新たなキー入力状態にするための2行でした。
・getchar関数とputchar関数は1文字の入力と表示
1文字のキー入力と、画面表示は、scanf関数とprintf関数で「%c」という書式指定子を書く事でプログラムできますが、getchar関数とputchar関数を使うことで、プログラミングが楽になります。
・EOF入力する迄繰返すプログラムの書き方を覚える
キーボードからEOF入力する、という操作はあまりしませんが、ファイル入力のプログラムでは、よく使うやり方になります。文字は1バイトなので、char型ですが、EOF(End Of File)というデータはint型の幅が必要なため、EOF判定する文字は、int型の変数で扱うようにします。
繰返しの条件の式で、代入式を書く書き方は、よく使う書き方になります。代入式を( )で囲む必要があるので、注意しましょう。
文字キー入力を、EOFが入力されるまで繰返すプログラムを作成しましょう。なお、入力した文字に対して、以下の対応をしましょう。
英大文字を入力した時は英小文字に変換
英小文字を入力した時は英大文字に変換
改行を入力した時は、改行表示後、入力促進メッセージを表示
数字はそのまま表示
*を入力した時は、*と改行文字を表示後、プログラム終了
上記以外の文字は表示しない
乱数を使ってランダムな文字を表示、プレイヤーに同じ文字を入力させるゲームを作りましょう。なお、このゲームを10回繰返し、その結果の正解数と不正解数とかかった時間を表示するようにします。
拡張問題1
正解数と不正解数とかかった時間を表示した後、再チャレンジするかきいて、ゲームを繰り返しできるようにしてみましょう。
拡張問題2
数字入力は簡単なため、ランダムな文字に数字を含めない様にしたり、ランダムな文字は記号だけにする等、工夫してみましょう。
繰返し処理を使った基本アルゴリズムの1つである「合計と平均」のプログラムを説明します。
データの個数が決まっている場合は、N回繰返すプログラムを応用したプログラムになります。合計を求める場合、合計を計算するための変数を用意して、最初に0をセットし、繰返しの中でデータを加算していきます。
データの個数が決まっていない場合、ある特定のデータを入力したら入力終了とみなす、という方法がよくとられます。下記の動画では、0を入力する迄繰返す様にしています。この0を入力する迄繰返す、というプログラムは、「無限ループで途中break方式」と「先読み方式」という、2つの代表的な書き方があります。プログラムには、定型的な書き方(アルゴリズム)があるので、以前も言いましたが、こういった定型的な書き方を覚えておくとプログラミングが楽になります。
ここでは、「3.1 プログラムの実行方法」で紹介したコマンド実行方式でプログラム実行するようにしています。理由は、コマンド実行方式では、入力リダイレクションと呼ばれるものを使うことができ、大量データを、キー入力ではなく、ファイル入力に切替えて実行させることが出来ます。入力リダイレクションは、キー入力をファイル入力に切替えるものですが、出力リダイレクションと呼ばれるものもあり、画面表示をファイル出力に切替えられます。
本節の練習問題は、コマンド実行方式でのプログラム実行を行っています。練習問題18では、プログラムを自動生成するプログラムを作成します。「まとめて何かしたい」といった時に便利なやり方になりますので、参考にしてみてください。
合計と平均を求める3種類の書き方を説明しています。
個数が決まっているデータの合計と平均
個数不定の合計と平均(無限ループ途中break方式)
個数不定の合計と平均(先読み方式)
CSV形式(カンマ区切り)のデータを入力する時は書式指定に「"%d,"」の様に、「,(カンマ)」を書かなければならないので注意してください。
・決まった個数のデータの合計と平均を求める
for文の式1、式2,式3の部分はN回繰返すロジックの中の、1からスタートカウントアップ方式の書き方になっています。
合計を計算するためのsumを繰返し前に0をセット、繰返しの中で、+=演算子でデータを足しこむことで、sumがデータの合計
・不定個数のデータの合計と平均(無限ループ途中break方式)
何回繰返すか分からないため、for文にしていません(for文で書くこともできます)。
無限ループにした場合は、ループの中のif文で「ループが終了する条件」を書いてbreakするようにします。
・不定個数のデータの合計と平均(先読み方式)
ループの外で先読みすることで、ループ処理を単純化できます。
ループの条件は「ループが継続する条件」を書きます。
「無限ループ途中break方式」のif文の条件と、先読み方式のwhile文の条件は、逆の条件になります。
・入力リダイレクションでファイル入力できる
scanf関数やgetchar関数は、キー入力しますが、これは標準入力と呼ばれるものです。標準入力は、コマンド実行方式でプログラムを実行する場合、入力リダイレクションというやり方で、キー入力をファイル入力に切替えることが出来ます。
・出力リダイレクションでファイル出力できる
printf関数やputchar関数では、画面表示しますが、これは標準出力と呼ばれるものです。標準出力は、コマンド実行方式でプログラムを実行する場合、出力リダイレクションというやり方で、画面表示をファイル出力に切替えることが出来ます。
・入出力リダイレクションでバッチ処理できる
ファイルを入出力するプログラムは、C言語応用編で勉強しますが、入出力リダイレクションを使うと簡単なファイル入出力が行えます。scanf関数はEOFを検出してくれるので、EOFでない間繰返すことでファイルの終わりまで入力するプログラムを作ることができます。
30個のカンマ区切りの整数データ(CSV形式)をファイルに作成し、OSの入力リダイレクション機能を使って入力、合計と平均(小数点以下2桁表示)を求めるプログラムを作成しましょう。
入力リダイレクションを前提としているため、入力促進メッセージは不要です。また、データはカンマ区切りで10個表示したら改行しましょう。但し、30個目のデータの後ろのカンマは表示しない様にしてみてください。
ほgw
カンマ区切りの整数データ(CSV形式)をファイルに作成し、OSの入力リダイレクション機能を使って入力、合計と平均(小数点以下2桁表示)を求めるプログラムを作成しましょう。なお、ファイルに入っているデータの個数は不定とします。
練習問題16と同様、入力促進メッセージは不要で、データはカンマ区切りで10個表示したら改行、最後のデータの後ろのカンマは表示しない様にします。
入力リダイレクションの機能を使ってアスキーアートのファイルを入力し、このアスキーアートを、printf文で表示するプログラムを作成しましょう。
なお、動画で使用しているアスキーアートのファイルと、アスキーアートのテキストに変換する前の画像ファイルは、以下からダウンロードできます。
for文を入れ子にした二重ループにすると、二次元の図形が表示できます。外側のループカウンタは行位置をカウントし、内側のループカウンタが桁位置をカウントします。
半角文字を使って表示する場合、半角文字の横と縦の長さが1:2の関係になっているため、表示する文字と半角スペースを組み合わせた文字列を表示すると、図形の形が整います。
カウントアップ方式のループやカウントダウン方式のループを組み合わせることで、四角形、三角形、逆三角形の図形を表示できます。
二重ループにより、図形が表示するプログラムの流れを、変数の動きと、画面に図形が表示される動きを説明しています。
様々な形の図形を表示するプログラムを通して、for文のカウンタの使い方を学びます。
・四角形を表示するプログラムが基本です
for文の2重ループで四角形が表示できます。
三角形、逆三角形、三角旗といった図形は、この四角形のプログラムを少し手直しするだけです。
辺の長さ(2以上10以下)を入力し、右記に示す図形を表示するプログラムを作りましょう。
なお、辺の長さに相応しくないデータが入力された場合は、エラーメッセージを表示し、再入力するようにしましょう。
テスト実施フォーム ← テストチャレンジできます
上記テストの解説と解答