C基礎5 色々な形の図形表示(関数)
C基礎5 色々な形の図形表示(関数)
「4 繰返し処理」では、四角形、三角形などの基本的な図形を表示しましたが、本章では、もう少し複雑な図形を表示します。図形表示では、同じ様なロジックを何度も書くことになります。同じようなロジックを「関数」という形にすると、プログラミングが楽になります。また、エスケープシーケンスという技を使い、色付け表示を行ってみます。
プログラムは少しずつ作っては、ビルドと実行を繰返しながら、徐々に大きなプログラムへと成長させていきます。複雑な図形を表示するプログラムを作る時に、小さく産んで大きく育てるプログラムの作り方を実感してもらいます。
動画は、Windows10とVisualStudio2019を使った説明になっていますが、WIndows11とVisualStudio2022を使った場合の操作方法と同じです。
同じ様な処理を「関数」というかたまりにすることを「関数化する」と言います。
関数化では、大きく以下かの3つが必要です。
関数定義を作る
関数プロトタイプ宣言する
関数呼出しする
「関数呼出し」は、今までは、printf関数やscanf関数といった、Visual Studioが用意している関数を呼び出していましたが、これからは、自分で作った関数も呼び出せるようになります。「関数定義」は、プログラムそのもので、「関数プロトタイプ宣言」は、関数呼出しする準備になります。
関数化では、以下に示す文法的な言葉が登場するので、言葉とその内容を理解するようにしましょう。
仮引数
関数定義する時に宣言する引数で、関数呼出しで指定した実引数を受け取る箱を用意するための宣言。仮引数に「void」と書くと「引数無し」になる。
実引数
関数呼出しする時に渡す値で、文法的には式になる。「仮引数無し」の場合、実引数には何も書かない。
復帰値(戻り値、return値)
関数定義の中で、returnする時に指定する式の値。return文が無い、または、「return;」の様に式を書かないreturn文の場合は、「復帰値無し」となる。
関数の型
復帰値のデータ型。「復帰値無し」の場合、関数の型はvoid型になる。
関数の書き方を学びます。
関数呼出しすることで、関数定義したプログラムが動き始めます。関数定義の中のreturn文が実行されると、呼出し元に戻ります。このプログラムの流れを説明しています。関数の書き方だけでなく、プログラムが、どの様に動くのかもイメージできる様にしましょう。
・関数プログラムは関数定義に書く
今まで書いていたmain関数は、mainという名前の関数定義を書いていたことになります。mainという名前の関数は、必ず、作成しなければなりません。
main関数以外にも、関数を作ることができます。関数の名前は、変数の名前と付け方と同じルールでつけることができます。
・関数定義する時、仮引数宣言を書く
引数が無い場合は、voidと書きます。
引数がある場合、引数の個数だけ、仮引数宣言を書きます。仮引数宣言は、関数呼出しした時の実引数を受け取るための箱を用意するための宣言なので、箱の種類であるデータ型と、箱の名前(仮引数名)を書きます。仮引数名の名前の付け方ルールは、変数の名前の付け方ルールと同じです。
・関数定義する時、復帰値(戻り値)と関数の型を書く
復帰値が無い場合、関数の型としてvoidを書きます。
復帰値は1個しか書けません。復帰値は「式」で、そのデータ型を関数の型として、書きます。
・関数呼出しで実引数が仮引数の箱にセット、returnで復帰値が呼出し元に渡される
関数呼出しからreturn迄のプログラムの流れをイメージできるようにしましょう。
・mainは関数定義群の最初に書くか、最後に書く
関数定義は、幾つも書く事ができます。
関数定義を書く順番に文法はありません。好きな順番で書くことが出来ます。ただ、作法としては、main関数は、最初に書くか、最後に書くようにしましょう。main関数を途中に書くのは無作法(行儀がよくない)です。
・関数プロトタイプ宣言は最初に書く
関数プロトタイプ宣言は、関数呼出しする位置よりも前に関数定義があれば、省略することができます。
ただ、関数プロトタイプ宣言があると、どの様な関数を定義しているかが分かるので、省略せずに書いた方がよいでしょう。
練習問題19で作成したプログラムを関数化しましょう。
図形の大きさを入力する処理は、このプログラムの中では一カ所しかありませんが、他のプログラムでも使うことが出来そうなので関数化しましょう。この様に、他のプログラムでも使えそうなものは、関数定義の形で書いておくと、他のプログラムで流用しやすくなります。
図形を表示するプログラム部分では、同じような記述が幾つもあるので、関数化してみましょう。
また、四角形表示、三角形表示など、処理の塊も関数化すると、プログラムが読みやすくなります。
ダイヤ形、六角形、八角形は、単に*を表示するだけでなく、スペースを行毎に何個表示するかを考える必要があります。空白と*を何個表示するかのカウンタを2つ使うやり方を紹介します。
for文のループの中で、2つのカウンタを使う場合に便利なのが「,(カンマ)演算子」です。式をカンマでつなげると、式にすることができます。カンマ演算子は、+演算子などと同じ様に、式を書くことができる所で使えますが、for文の式1と式3の所で使うことが多いです。
八角形を表示するロジックをベースに、真ん中の四角形を表示するか否かで、六角形やダイヤ形にすることができます。このため、関数を1つ作成し、引数を工夫することで、ダイヤ形、六角形、八角形を表示することができます。
空白をカウントするカウンタを追加し、ダイヤ形、六角形、八角形を表示するロジックを説明しています。
このロジックを1つの関数に仕立てて、この3つの図形を表示するプログラムに変化させます。
引数を変化させることで、プログラムのロジックをまとめるやり方になります。
・*の数と空白の数を意識する
*の左側にある空白の個数が、どの様に変化するのかも調べる必要があります。
・カンマ演算子は二項演算子です
カンマ演算子は、for文の式1と式3の所で使うと、複数のカウンタを扱うことができます。
・六角形は、ダイヤ形の*数が、一定数、横方向に多い形
図形を表示するプログラムを作る場合、基本となる図形を探し出し、その基本図形との違いを明確にしていきます。
・八角形は、六角形の上部と下部の間に長方形がある
違う部分が、どの様な図形で、その大きさがどの様な式で表わすことができるのかを、導き出します。
・図形のベースの長さを仮引数にして式を作る
関数化する時、仮引数を何にするかは、色々な方法があります。今回の例では、左記の様な引数にしました。
print_space関数は、引数で指定した個数の空白を表示する関数です。print_line関数は、引数で指定した個数の*を表示し、最後に行替えする関数です。
・関数呼出しする時の実引数を変化させる
関数呼出しする時の実引数に、所定の式を書くことで、ダイヤ形、六角形、八角形を表示することができます。
複雑なプログラムを作る場合、いきなり完成形を目指すのでは無く、プログラムを少しずつ変化させ、ビルドと実行を繰返しながら完成系に近づけていきます。
左右対称の三角形を、ピラミッド形に3段重ねた図形にします(三角三段ピラミッド)。
プログラムを少しずつ変化させながら、三角三段ピラミッドを作っていきます。
プログラムは、小さく産んで大きく育てるように作りましょう。
・基本となる左右対称の三角形を見つける
先ずは、基本となる三角形を表示します。
三角三段ピラミッドは、この基本の三角形を6個から構成されています。
・縦横に同じ図形を繰返し表示する
基本の三角形を、横に繰返し表示するfor文と、縦に繰返し表示するfor文がネストします。
・段ごとに表示する三角形の個数を増やす
横に繰返し表示する三角形の個数を、1,2,3と変化させます。
・段ごとに表示する空白の個数を追加する
段ごとに、一定個数の空白を表示するロジックを追加することで、三角三段ピラミッドが完成します。
C言語の文法ではありませんが、色を付けて表示したり、文字を表示する座標位置(カーソル位置)を、指定した位置に変化させる技があるので紹介します。
Windowsで動かすプログラムは、ESC文字からの定められた文字列をprintf文で表示すると、画面の表示上は何も表示されませんが、特別な表示状態にさせることができます。このESC文字からの定められた文字列をエスケープシーケンスと呼んでいます。今回紹介するエスケープシーケンスは、VT100ターミナルシーケンスとも呼ばれる方法で、Windowsだけでなく、他のOSでも可能となるやり方です。
実験的なプログラムを通して、色付けしたり、カーソル位置を変更したりするエスケープシーケンスを紹介しています。
・目に見えない文字は16進または8進の文字定数表現
ESC文字の様に、目に見えない文字を文字定数で表現する時は、16進数か8進数で表現します(10進数では表現できません)。
エスケープシーケンスを開始するESC文字は、ASCIIコードの27(10進)で、16進の「1b」、8進の「33」になります。このため、エスケープ文字を文字定数で表わすと、16進表現では「'¥x1b'」、8進表現では「'¥033'」になります。
・エスケープシーケンスはprintf文の文字列で指示
使えそうなエスケープシーケンスを左記に示しています。
エスケープシーケンスは、ESC文字から始まる複数の文字の並びになるので、printf関数で文字列として書くようにします。
・画面制御のエスケープシーケンスを有効にする
プログラムの最初に「system("cls");」をしましょう。
Visual Studioを経由したプログラム実行の場合、コマンドプロンプト画面はエスケープシーケンスが有効な状態になっていますが、エクスプローラで直接プログラム実行した場合、エスケープシーケンスは無効な状態のため、エスケープシーケンスをprintfすると、文字化けが発生します。「system("cls");」をすると、エスケープシーケンスが有効になります。
マクロ定義は、#defineを使って、プログラムの記述に対して名前を付けるものです。プログラムを実行する時の命令ではなく、コンパイラに対する指示になります。このため、関数定義の中には書かずに、#includeの記述の後に書きます。
エスケープシーケンスは、謎の文字列のため、見ただけでは何の命令なのかが分かりません。こんな時、マクロ定義を使ってエスケープシーケンスをprintfする関数呼出し式に、何をするエスケープシーケンスなのかを意味する名前を付けることで、プログラムを読みやすくすることが出来ます。
マクロ定義の詳細については、C言語応用編で説明します。
マクロ定義を使って、エスケープシーケンスに名前を付けるプログラムの書き方を紹介します。
関数化することで、エスケープシーケンスを使ったプログラムを分かり易くする方法も説明しています。
・#defineを使ってマクロ定義する
マクロ定義でマクロ名を付けます。通常、マクロは英大文字の名前を付けます(作法)。
名前の付け方ルールは、変数名の名前の付け方ルールと同じです。
図形の大きさを入力後、画面クリアしてから指定された大きさの図形を色づけして画面の中央に表示するプログラムを作成しましょう。
色は、自分の好きな色でもよいですし、乱数から求めた色でも良いでしょう。図形表示後、Enterキーを押したら、再度、図形の大きさを入力して図形表示を繰返す様にして、何度も、図形を表示できるようにしてください。図形の大きさに0を入力したら、プログラムを終了する様にします。
練習問題21で使うエスケープシーケンスのマクロ定義や関数を作っていない方は、右記のプログラムをダウンロードして流用してください。
エスケープシーケンスは1文字でも間違えると文字化け状態になります。自分で記述する時は、英大文字と英小文字の違い、数字の1と英小文字のlの違い、数字の0と英大文字のOの違い等に気を付けて記述ください。
練習問題21と同じ様に、図形の大きさを入力後、色付けした図形を表示しますが、今度の図形は、同じ図形を画面一杯に縦と横に繰返し表示するようにしましょう。
画面のサイズは、横が80桁、縦が25行とし、その中に収まる様に表示できる図形の数を、計算で求めるようにしましょう。
テスト実施フォーム ← テストチャレンジできます
上記テストの解説と解答