[前回の内容] 前回(2019/05/31)の内容 「繰り返し」の復習 : 再帰呼出しする関数の定義は「繰返し」を表現 再帰呼び出し 関数を定義する時(その関数はまだ未定義..)に、 その定義の中で、自分自身を呼び出す。 # 今のプログラミング言語では、「できる事が常識」 # 古い言語 (Fortaran, Cobol, BASIC, etc.. )はできない => 自分が呼び出されると、自分が「再度」呼び出される => 自分の中身が、繰り返される => 「中身」の部分を繰り返すために、「再帰」を利用する => 順接/条件分岐/繰り返し(再帰呼び出し)の三つの制御構造によって、万能になる 講義(ソフトウェア概論)の目的 => プログラムが書けるようになる プログラム <=> 命令の並び => 「基本命令」と「その組み合わせ方法」の両方ができればよい 基本命令 => いろいろな API (ライブラリの利用) [単語の学習] 組み合わせ方法 => 制御構造三つあれば、完全 [文法の学習] => 一通りの内容が終わっている # 他の言語でも同様(基本命令:ググる/制御構造:三つの表現を理解する) [今後] 基本命令 : API => 今後も色々紹介したい 制御構造 : 同じ事をする、もっと便利な表現がある => 自分がプログラムを書く場合は、(便利だけど..)不要だが、他の人のプログラムを読むために必要 => プログラムを学ぶ上で、最も有効な方法は、 他の(優秀な)人の書いたプログラムを読んで、 (変更を加えたうえで)実行する プログラム : 命令の組み合わせ 命令 : 何[対象 : Object] をどう[動作] する 今まで : 対象を「文字列」に限定していた => 対象のバリエーションに着目して話をしてゆく [文字] 「文字列」とは異なる 例:「文字列」が長さをもっているが、「文字」は、つねに一つのもの 「文字列」は +1 すると、長さが短くなる、「文字」は次の「文字」になる 「文字列」から「文字を取り出す」事できる 「文字」の扱い : C 言語では「文字列」以外に「文字」が扱える 文字のリテラル(文字自身の表現) : 「'」+「一文字」+「'」 例 : 「'A'」という表現は、「A」という「文字」を表す 文字の入出力 : getchar/putchar 関数で、文字が入出ができる [今週の話] 「文字」について続き 「(半角英数記号)文字」は、「ASCII 表に従って、小さな整数と 1 対 1 対応になっている」 # 「小さな整数」は、「ASCII 表では、0 〜 127 の値」=> 1 byte に入る # => 128 種類の「文字」しか扱えない # => キーボード上の 文字の数に対応している # <= 全角文字(日本語)の個数には対応していない # => もし、「日本語」を表現するとすると 1 文字を 1 byte では表現できない # => 一文字を 2 byte で表現する事になる # !! 最近 C 言語では、wchar 1 byte に入らない文字を扱えるようになっているが、 # !! => この講義では扱わない 実は、C 言語では、「文字」と小さな整数値(1 byte 内)は「ASCII 表」を通して、 (ほぼ)同じものとして扱われる putchar ( '0' ) と putchar ( 48 ) は同じもの ! コンピュータ「計算機」は、「計算」しかできない ! 「計算」(狭義では..)は「数」の処理を指す ! => 計算機は「数」しか扱えない ( 今でも、本質的には、そう.. ) ! なぜ、今のコンピュータは、数以外のものがあつかえるか ! => 「コーディング」(数といろいろな情報の対応表[Code 表]があり、 ! 「情報」を、この「Code 表」で、対応付ける事により、 ! 間接的に「情報」の処理ができているように見せている ! 情報を処理する時に、「どの表を使うか」は、予め決めおく必要がある ! => これが違っていると混乱することになる ! windows では、全角を表現するために SJIS (Shift JIS)を利用するが、 ! ubuntu では、UTF-8 を使う (ので、文字のコード表が異なる)ので注意 == [make と makefile] C 言語の話ではない C 言語でプログラムを作成するときに利用する便利ツール 「C 言語でプログラムを作成するときに利用するツール」として cc を知っている cc の使い方を覚えた ( cc -c でコンパイル、cc -o でリンク..) => C 言語で作成したプログラムを実行する事が可能となる C 言語で呼び出す関数は、どこかで定義されている必要がある printf は、実は(別の所で定義され..)標準ライブラリに収められているので、 cc が、リンク時に、その標準ライブラリの中から、取り出して利用している !! 標準ライブラリ内の関数は、定義せずに使えるので便利 !! cf. printf/putchar/getchar !! => C 言語の標準的な知識の一部は、標準ライブラリの APIを学ぶ事 もし、定義されていない関数を呼び出すと、リンク時にエラーになる C のプログラムを作るときに、 関数を利用する場合は、その関数が定義されている必要がある しかし、その定義は、同じプログラムファイルの中になくてよい cf. 標準ライブラリの中の printf は、定義しなくても使える そこで、 関数を定義する C ファイルと利用する C ファイルを別々して、 後で(リンク時)にまとめる事ができる => 分割コンパイル 例: p-006.c は一つのファイルの中に print_hello_to の定義と利用が一つにまとまっている => 一つのファイル一度コンパイルして、リンクしれば実行ファイルが作れる p-007.c と p-007-01.c は、p-006.c の関数定義と参照を別のファイルにした # 分割は、基本、関数単位(関数の一部だけを別のファイルにするわけではない..)に行う => それぞれの C ファイルをコンパイルして、リンク時にすべてのオブジェクトファイルを指定すればよい p-006.c => p-006.o => p-006.exe | +- p-007.c => p-007.o -+-> p-007.exe +- p-007-01.c => p-007-01.o -+ 分割コンパイルのメリット 関数定義を再利用できる => 一度定義した関数は、完成していれば、一度コンパイルするだけで、 それを他のプログラムでも利用できる !! 「ソフトウェア工学」 !! => プログラムの生産性を高める !! => プログラムの再利用 !! # 分割コンパイルは、そのための典型的な手法 デメリット: 実行ファイルを作る手間が増える # 「手間」は、「同じ」なら、我慢できるが、「個々に違うといや」 => 実行ファイルを作る個別の内容に関しては、 1. それを記録して、間違いないようにする Makefile 2. 1. を利用して、自動化する make Makefile が用意されていれば、 make とするだけで、自動的に必要なコマンドを実行してくれる [まとめ] 分割コンパイル : プログラムを複数のファイルに分けて記述し、 実行ファイルを作成する(リンク)時にまとめるという考え方 => プログラムファイルの再利用がやりやすい <= 作業内容が複雑になる => Makefile と make によって、その複雑さを回避し、さらに簡単になる !! 作業内容をドキュメント化し、さらに自動化をしている Hanoi 等の API が、いろいろな手順を要求する可能性があり、 その場合には、makefile と make が重要な役割を担う !! 資料の中に makefile があったら、とりあえず、 make する == ハノイ塔 大きさの違う円盤が何枚か(ここでは 3 枚)が、1の棒に小さい円盤が 大きい円盤の上にあるようにおかれている | | | *|* | | **|** | | ***|*** | | ======================== 1 2 3 目的 1 の三枚の円盤をすべて 2 に移動したい 規則 a. 円盤は一度に1枚しか移動できない b. 小さい円盤の上には、大きな円盤を乗せる事ができない どのようにすれば、すべての円盤を移動させる事ができるか ?