Dokusyo-nissi Bessitu 2007-05-06 φ(-_-) ■[lang]はじめての C [Learning GNU C] 2.4. 自分だけの関数をつくろう 前の例題では関数を 1つだけ定義した。別の関数を加えるには通常 2つのことが必 要だ。 1つ目はちょうど main() を定義したようにその関数を定義 define しない といけない。またそれを宣言 declare しなければならない。関数の宣言とはその要 求を GCC に伝えるようにすることだ。 main() についてはそれが特別な関数であり GCC が要求を理解しているという理由から宣言する必要はない。関数に与える名前 あるいは識別子 identifier は定義と宣言の両方に現われないといけない。 関数の識別子にはアルファベットの 'a' から 'z' と 'A' から 'Z'、数字の '0' から '9' まで、それにアンダースコア '_' を使うことができる。これらは識別子 の最初の文字が数字でなければどんな順序でも用いることができる。以前いったよ うに C は大文字と小文字を区別する case-sensitive ので "My_Function" と "my_function" は全く異なるものだ。関数の識別子は固有のものでなければならな い。識別子は短いほうは文字 1つから 68文字の長さまでが安全な (範囲) だ。 識別子とともにそれぞれの関数へは型 type と code の block を渡さなければなら ない。型は compiler にどんな種類の data を返すのかを伝える。関数の返り値は 無視することができる。 printf() ではどれだけの文字数が terminal に表示され るかその整数値を返す。この情報は重要でないのでわれわれのプログラムでは無視 された。次の章では data の型を詳しく検討しよう。それまでは返り値を適当に扱 う gloss over ことにしよう。 これが 3つの関数を定義するプログラムだ。 Example 2-3. three_function.c #include /* 関数の 宣言 */ int first_function(void); int goodbye(void); int main() // 関数の 定義 { printf("the program begins ...\n"); first_function(); goodbye(); return 0; } int first_function() // 関数の 定義 { /* この関数は なにも しない */ return 0; } int goodbye() // 関数の 定義 { printf("... and the program ends.\n"); return 0; } 上の例題ではなにも行なわない first_function() と message を表示する goodbye () を書いた。関数ではそれぞれが呼び出される前に宣言されないといけない。この 場合それは main() の定義 (より前に?) 現われる必要があることを意味する。実際 関数の宣言は通常 #include の line の後、どの関数の定義よりも前に file の先 頭部分へ集められている。 2007-05-09 φ(-_-) ■[lang]はじめての C [Learning GNU C] 2.5. さまざまなファイル プログラムは 1つのファイルで書かなければならないことはない。 code は思うよ うに多くのファイルに細分することができるので 1つのプログラムを 40個の関数で 構成したとしてもそれぞれの関数を別々のファイルに入れることが可能だ。これは 少し極端だが。関数はしばしば課題 topic ごとに集められ別々のファイルに入れら れる。たとえば pizza の単価を算出しその結果を表示するプログラムを書いていた とすると計算する関数を 1つのファイルに、表示する関数を別のそれに入れ 3つ目 を main() とすることができる。プログラムをコンパイルするため使われるコマン ドはこのように表されるだろう。 ciaran@poor:/~book$ gcc -o pizza-program main.c prices.c display.c ciaran@poor:~/book$ 留意点: prices.c で関数を定義しこの関数を main.c から呼び出したいときはその 関数を main.c のなかで宣言しておかないといけない。 2.6. ヘッダファイル 関数の宣言が混乱して見失いことのないよう -- そのためには -- さまざまなファ イルで現われることのできるよう C の code を収めるためヘッダファイルが用いら れる。 stdio.h は多くの関数の宣言を収めたヘッダファイルでありそこには printf() や printf() の(?) 関数の宣言が含まれている。一度共有したい関数の宣 言をしておけばその情報を必要とする各々の C のファイルのヘッダへ収める -- # include -- ことができる。ファイルの名前を取り込むとき (標準関数と) ただ 1つ 違うのは angle bracket のかわりに quote を付ける ( のかわ りに "my_header.h" とする) ことだ。これらの要点を説明するため先にふれた pizza-program を書こう。 2007-05-12 φ(-_-) ■[lang]はじめての C [Learning GNU C] 2.7. より大きな (未完成の) プログラム 今まで見てきた小さなプログラムの規模ではある程度の対話型プログラムをつくる には十分でない。簡単にしておくためにプログラムの骨組みを書くことにしよう。 そうすれば新しい考え方で泥沼にはまることなくその構造と使い方とを理解できる 。第3章でこのプログラムの完成版を書く。ここにある code はコンパイルして実行 できるがそれはユーザになにか入力を求めたり価格を算出したりはしない。 初めは main.c だ。これはただ関数 main() からできている。 main() は他のファ イルで定義したいくつかの関数を呼び出していく。注意するのは the Standard Device I/O ライブラリからの関数はなにも使わないので #include という line をもたないことだ。 Example 2-4. main.c #include "display.h" #include "prices.h" int main() { display_options(); calculate_price(); display_price(); return 0; } 次は display.c だ。これは 2つの関数からなりいずれも main() から呼び出すので ヘッダファイル display.h にこれらの宣言を置く。 Example 2-5. display.c #include int display_options() { printf("pizza parler へ ようこそ。\n"); printf("pizza の サイズ (inch) は どうしますか?"); return 0; } int display_price() { printf("pizza の お値段は 0.00 と なります。\n"); return 0; } Example 2-6. display.h /* ヘッダファイルは 関数の 宣言から なり これらの * 関数の どちらかを 用いるときは このファイルを * "#include" しなければ ならない。 */ int display_options(void); int display_price(void); 最後が prices.c でそれはユーザからの入力を受け取る関数と pizza の総価格を算 出する関数からなる。 main() から呼び出すのはただ 1つの関数だけでそのため他 の 2つの宣言はファイルの先頭に置く。これらの関数の code は第3章で埋めていく 。 Example 2-7. prices.c int get_size(void); int get_toppings(void); int calculate_price() { /* code を ここに 置く。get_size() と * get_toppings() を 呼び出す。 */ return 0; } int get_size() { /* code を ここに 置く。 */ return 0; } int get_toppings() { /* code を ここに 置く。 */ return 0; } Example 2-8. prices.h int calculate_price(void); 次にコマンドでコンパイルする。 $ gcc -Wall -o pizza-program main.c prices.c display.c 実行するとあいさつを表示して pizza の金額が "0.00" だと知らせる。 2007-05-13 φ(-_-) ■[lang]はじめての C [Learning GNU C] 2-8. もう1つの新しい関数 先に進む前に the Standard Device I/O ライブラリからさらに 1つの関数 -- printf() -- を見ることにしよう。この「表示を書式化する」 print formatted コ マンド (の line) は printf() の進化した書式 advanced form だ。 printf() に 渡された文字列では特定の意味をもつ文字の綴りを構成することができる。 printf () と異なり ?? そこでは printf() により表示される文字列の終わりは自動的に改 行されないので改行を差入れるため "\n" という文字を追加している。 2-9. 教材の要約 今まで述べたことはむずかしすぎることはないだろう。もし試してみたいなら line を数行出力する同じようなプログラムを書いてみる。プログラムを 1組の関数に分 けそれを 2つのファイルになるように工夫すること。 プログラムをコンパイルするとき GCC はいつでも警告が可能だ。警告はプログラム の code がはっきりしていないか不完全なことをさし示す。 GCC は正確な意味あい を推測して通常それを正しくするよう促すだろうがこれは当てにできない。見直し 訂正することで警告はこの言語が使えるようになるのを助けるだろう。ほとんどの 警告にはどこで問題があったかその line number (行番号) が伴う。仮りになにが 悪いかがわからなければそれより上の line を調べる。命令文が不完全だと GCC は その次の命令文の初めにぶつかるまではそれがエラーだと通告できない。セミコロ ンは忘れないこと。 2007-05-15 φ(-_-) ■[lang]はじめての C [Learning GNU C] 第3章 data と式 実際に役にたつプログラムは data を取り入れそれに作業を加えそしてそれをどこ かに出力する。 C では data を保存するため変数 variable と呼ばれる名前をつけ たメモリの区画 piece を用いる。 C のプログラムではその名前のとおり変数に保 存された data はいつでも変更することができる。全ての変数はその値を使用ある いは変更したいときその data を参照して用いることができるよう識別子 identifier (名前) をもつ。式 expression とは -- すなわち "1 + 1" が '2' の 値を表す expression ように -- 数値を求めることができるものだ。この式のプラ ス記号は二項演算子 binary operator なのでそれは 2つの値を単一の値につくりあ げるよう働く。変数を名づけるための規則は関数 function を命名するそれと同じ だ。文字と数字そしてアンダースコア記号を用いることができ最初の文字は数字で あってはならない。また関数のように変数はそれが使われる前に定義されていない といけない。変数に与えられた識別子 (名前) は変数がなにに用いられるかを示す ことで code をとても読みやすいものにする。自分自身で変数を定義するかあるい はすでに定義されている型 type の 1つを (選び) 使うことができる。専門用語で 泥沼におちいる前に早々に全てがどれほど簡単かを示した code の例題を見てみよ う。この例題では前もって型を int に定義した 2つの変数を用いる。 Example 3-1. bicycles.c #include int main() { int number_of_bicycles; int number_of_wheels; number_of_bicycles = 6; number_of_wheels = number_of_bicycles * 2; printf("I have %d bicycles\n", number_of_bicycles); printf("So I have %d wheels\n", number_of wheels); return 0; } 2007-05-19 φ(-_-) ■[lang]はじめての C [Learning GNU C] 3.1. 自転車の分解 これを見るといくつか新しい点がある。これらを説明するためこのプログラムをカ タマリ chunk に砕いてみる。 int number_of_bicycles; int number_of_wheels; この 2つのline でそれぞれの変数を宣言する。 "int" とは C language に組み込 まれた data の型 type の 1つだ。 int 型の変数には正または負の全ての数が保存 できる。 number_of_bicycles = 6; この line では変数 number_of_bicycles に 6 の値を保存する。等号記号 '=' は 「代入演算子」 assignment operator でそれの右側の値を左側の変数に代入する。 nmber_of_wheels = number_of_bicycles * 2; この line でも同じく等号演算子が使われているがまたここでは乗算演算子 multiplication operator も使われている。アスタリスク '*' は別の二項演算子 binary operator でそれは 2つの値を掛け合わせて単一の値をつくりだす。この場 合は 12 の値を得て次に number_of_wheels に保存する。 printf("I have %d bicycles\n", number_of_bicycles); printf("So I have %d wheels\n", number_of_wheels); ここで再び printf() と会うがそれは以前見たものとは異なった使われ方をしてい る。先の 2つの引数はコンマによって区切られている。 printf() の最初の引数は 書式文字列 format string というものだ。書式文字列のなかで "%d" に出会うと printf() は別の引数が要求されたことを知る。 %d はその別の引数にとり変えられ る。それぞれ出会う %d には追加した引数が 1つ求められる。 この新しい知識があれば code のその部分をコンパイルし実行した際次のような (結果が) 得られても驚くことはないだろう。 I have 6 bicycles So I have 12 wheels いつものようにいくつかの箇所がアイマイでも心配いらない。多くの例題をたっぷ りしていこう。 2007-05-20 φ(-_-) ■[lang]はじめての C [Learning GNU C] 3.2. data の型 C によって定義される全ての data の型は byte と呼ばれる memory の単位からな る。多くのコンピュータ構造では 1 byte は 8 bits からなりそれぞれの bit は 0 または 1 を保持する。 2つの状態 (0 または 1) をもつこれらの 8 bits から 256 の組み合わせ (28) が生じる。そして 2 bytes を占める整数 integer では 0 から 65535 の間の数を保持することができる (0 から 216、しかし通常整数の変数はそ の最初の bit で数値が正か負のどちらかを保持するため使われるのでこれらの値は -32768 から +32767 の間になる)。 (次に) 述べるように C language には 8つの基本となる data の型が定義されてい る。異なるサイズの整数を保持する 5つの型と浮動小数点 floating point (小数点 を伴う) 値を保持する 3つの型だ。 C では text のための基本となる data の型は 用意されていない。 text は個々の文字からなり文字は数値によって表す。前の例 題では整数の型の 1つ "int" が使われた。これは C languahe ではもっとも普通に 用いられる型だ。 コンピュータプログラムで使う大部分の data は整数型からなるので浮動小数点を 論じるのは少し後とする。サイズの順序は整数型で最小のものから始めて "char"、 "short"、"int"、"long" そして "long long" だ。 (一般的に) より小さな型では わずかの memory しか占めないという利点があり大きな型では性能上の不利益をま ねく。 int 型の変数は可能なかぎり大きな整数を保持しても性能上の不利益をこう むらない。その理由は int の変数が使用するコンピュータの種類により (その大き さを) 違えることができるからだ。 char 型の data は通常 1 byte でそれは普通文字 character 1つ分を保持するのに 使われるためそう呼ばれる。多くの desktop 機は "32-bit" でこれ (bit数) は処 理のため設計された data のサイズを参照している。 int 型の data は 32-bit の machine 上では 4 bytes (232) を占める。 short は通常小さく long は大きくで きるかまたは int と同じサイズであり最後に long long は非常に大きな数を扱う 。 一般的に使われる変数の型では application の速度や memory 使用上に大きな影響 がない。特別の必要がなければほとんどで int 変数を使うことができる。この本で はそれが重要になるいくつかの事例を示すよう努める。 10年前は多くの machine が 16-bit の CPU をもちその int 変数のサイズは 2 bytes が限度だった。当時 short 変数は同じく 2 bytes で long は 4 bytes だったはずだ。現在 32-bit の machine では int 型の既定値 default は通常 long 型の変数の要求に使えるほど 十分大きい。 long long 型はごく最近非常に大きな数を扱うため導入された。 あるコンピュータでは非常に大きい数を扱うのにより適しているためそうした machine では data 型のサイズはずっと大きなものになる。 machine のそれぞれの data 型のサイズを調べるため (次の) code をコンパイルし実行する。これには新 しく sizeof() という言語要素 language construct が 1つ使われる。それは data 型を占める byte 数がいくらかを報告する。 Example 3-2. sizeof_types.c int main() { printf("sizeof(char) == %d\n", sizeof(char)); printf("sizeof(short) == %d\n", sizeof(short)); printf("sizeof(int) == %d\n", sizeof(int)); printf("sizeof(long) == %d\n", sizeof(long)); printf("sizeof(long long) == %d\n", size of (long long)); return 0; } 2007-05-22 φ(-_-) ■[lang]はじめての C [Learning GNU C] 3.3. 代入の別の例題 (ここで) 別の例題について時間を割(さ)こう。このちょっとした code では -- す ぐに説明するが -- ほんの少しより新しいことが示される。 Example 3.3. displaying_variables.c #include int main() { short first_number = -5; long second_number, third_number; second_number = 20000 + 10000; printf("the value of first_number is %hd\n", first_number); printf("the value of second_number is %ld\n", second_number); printf("the value of third_number is %ld\n", third_number); return 0; } 1つの short と 2個の long の変数を使った。 (今まで) int の変数が使えるよう にしたが他の型でもどれほどそれが似ているかを示すために用いてみた。 main の 最初の line では 1つの line の中で変数を宣言し値を渡す。わりとそのことは普 通だ。 2つ目の line ではコンマによって区切られた 2つの変数を同時に宣言する 。これは手際よくできるが多くの場合 code で変数を (複数) 宣言するときにはし ばしば 1つの line に (まとめて) 用意する。 3つ目の line は最初の例題にある code と全く似ていて加算演算子により 30000 の値が得られ second_number に保存される。最後に注意するのは "%d" に代わり printf() の書式文字列が short 変数では "%hd"、long 変数では "%ld" を含むこ とだ。こうした小さな (2つの) 文字の組み合わせを変換指定子 conversion specifier と呼ぶ。変数の型はそれぞれ自らの変換指定子をもつ。パーセント記号 を単体で表示したいときには "%%" と書かないといけない。 コンパイルし実行すれば変数の値がわかる。 third_number の値 (だけ) が見慣れ ないものだろう。これは値が全く代入されなかったことによる。変数を宣言すると OS はなんらかの memory をそのために割り当てる。使われた memory が前もってな にかを知る方法はない。変数に値を渡すまでは実際にはそこに保存された data は random になる。変数に値を代入することを忘れるのは初心者のプログラマによくあ るミスだ。 2007-05-27 φ(-_-) ■[lang]はじめての C [Learning GNU C] 3.4. printf() の手早い説明 printf 命令文の終わり近くの 2つの文字 "\n" に気づいたと思う。これはスクリー ン上には表示されない、printf() で改行を表す記号だ。 '\' (バックスラッシュ) は引用符 (" ") 内で出会う C のエスケープ文字で (それの) 次の文字は普通特別 な意味をもつ。別の例では "\t" は TAB を表すのに使われる。 他に printf() で注意する特別の文字に '%' がありそれに続くある文字を見つける とこれと変数の値とを取り換える用意をする。 "%d" は int 型の変数を取り換える 文字の綴りで 10進法 dicimal counting システムを使って表示される。書式文字列 のなかの全ての "%d" では取り換えたい変数はなにかを printf() に知らせないと いけない。 code での printf() のいくつかの使い方がこれだ。 Example 3-4. more_printf.c int main() { int one = 1; int two = 2; int three = 4; /* ここでの 値は 重要ではない */ printf("one ==\t%d\ntwo ==\t%d\nthree ==\t%d\n", one, two, three); return 0; } 3.5. 簡単な計算法 この章の初めで触れたが通常プログラムの要点 point には data に作業を加えるこ とが含まれる。一般的な数字記号を使うことで C での計算は読みやすくなる。 Example 3-5. wages.c int main() { int hours_per_day; int days_per_week; hours_per_day = 8; days_per_week = 5; printf("I work %d hours a week.\n", (days_per_week * hours_per_day)); printf("%d %d hour days\n", days_per_week, hours_per_day); return 0; } 3.6. グローバル global 変数 これはそこ (= プログラム全域 global) で場所を占める (= 有効だ) が時には不適 切な code が書かれ使われてしまう。仮りに 2つの関数で 1つの変数を動かす必要 があるならそれを全ての関数で有効にするよりむしろこの変数が共有するポインタ を使うべきだ。 3.7. 静的 static 変数 (編集中) 3.8. 定数 constant 変数 守るべきルールの 1つに code のなかでは 1 か 0 以外の数をけっして使わないこ とがある。他の数字の定数 constant が必要ならそれを const 変数にしておく。こ れは意味のある名をつけるいいやり方だ。 (例えば) 40 という数字はわずかな意味 しかもたない。しかし HOURS_WORKED_PER_WEEK という識別子 (名前) なら関数がな にをしているかなんらかのことが示される。別の利点としては (プログラム中の) 全ての 40 を見つけて変換するかわりに const 変数を 1箇所で取り換えることがで きる。前の方法を用いると 40 とは関係のない箇所を変換したりある箇所を変換し 忘れたりする誤りが簡単に起こる。 2007-05-30 φ(-_-) ■[lang]はじめての C [Learning GNU C] 第4章フロー制御 (ある) 決定にもとづいた動作をとること。 C では分岐 branching とループ looping という 2種類の判定手段を備える。分岐 はなにを選択肢にとるかを決定しループはある一定の動作を何回くり返すかを決定 する。 4-1. 分岐 分岐は 1つの枝 branch か別の (どちらを) たどるかを選択するためこう呼ばれる 。 if 命令文は分岐命令文のなかでは最もやさしいものだ。それはマルカッコ "( ) " に式 expression を入れ (ナミカッコ "{ }" で囲んだ) 1つの命令文または命令 文のブロックを使う。その式が真である (ゼロでないと評価) ならこの命令文ある いは命令文のブロックが実行される。そうでなければこれらの命令文は飛ばされる (スキップ)。 if 命令文は次のような形をとる。 if (expression) statement; あるいは if (expression) { statement1; statement2; statement3; } これが -- 即製の -- コードの例題だ。 Example 4-1. using_if.c #include int main() { int cows = 6 if (cows > 1) printf("ウシを 飼ってます\n"); if (cows > 10) printf("それも いっぱい!\n"); return 0; } コンパイルし実行するとこのプログラムは (次のように) 表示する。 ciaran@poor:~/book$ gcc -Wall -Werror -o cows using_if.c ciaran@poor:~/book$ ./cows ウシを 飼ってます ciaran@poor:~/book$ 2つ目の printf() 命令文はその式が偽である (ゼロと評価) ので実行されない。 2007-06-03 φ(-_-) ■[lang]はじめての C [Learning GNU C] 4.2. if ... else if 命令文の 2つ目の形に条件式 test expression が偽のとき (別の) code のブロ ックの実行をまた指定させるものがある。これは "if ... else" 命令文として知ら れ通常の if 命令文の後に予約語 reserved word の "else" と別の code のブロッ クを置く形をとる。プログラムでは if の後ろの条件文にもとづく 2つの code の 内の 1つが実行される。どのように表すかがこれだ。 Example 4-2. cows2.c int main() { int cows = 0; if (cows > 1) { printf("ウシを 飼ってる\n"); printf("ちょうど %d 頭だけ\n", cows); } else { if (cows == 0) printf("全然 ウシは 飼ってない\n"); else printf("1頭だけ ウシを 飼ってる\n"); } if (cows > 10) printf("おそらく 多いはず\n"); return 0; } ここの出力は推測できるだろう。 ciaran@poor:~/book$ ./cows2 1頭だけ ウシを 飼ってる ciaran@poor:~/book$ この例題では 1つの if ... else 命令文の内側に別の if ... else 命令文がある 。これは C の理に適っていてまったく普通のことだ。別に使うことができる分岐の 形があるがそれはほんの少し複雑なのでこの章の最後に取っておこう。