かれこれ半年以上ぶりの更新。
というわけで、直接次の話を進めるのではなく、簡単な復習をしてみよう。
現時点でもかなりの量になっているため、今回もやはり長文になると思われる。
それでは、いつもの順に進めよう。やや題は異なるけれど。
復習概要
- プログラムは、指示の列である。当然最初があって、次があって、・・・と続く。
- C言語では「指示の開始地点」はmain関数と呼ばれる関数である。
- 関数は、名前のついた「指示の集まり」である。集まりとして記述するのだから、使うこともできる。
- 関数には「返り値」がある。関数を使った場所におかれる値で、関数の中でreturnを使って記述する。関数を作るときに、関数名の前にあるものが返り値の「型」(種類)である。
- 関数には「引数」があることもある。ないこともある。複数ある場合コンマで続ける。
- 関数の使い方には、そもそもC言語で書ける範囲を超えたものを書く、というものもある。たとえば画面に文字を出力するには、関数を使うしかない*1。
- 関数の中で自分を呼ぶことを「再帰」と呼ぶ。これで同じような処理を繰り返すことができる。
- ある条件で実行する指示が分かれることを条件分岐という。ここではifという語で条件分岐を作った。
・・・こんなものだろうか?かなりつめて説明しているので、これだけ読んでも何のことかわからない気がする。
簡単なmain関数
int main() { return 0; }
第一回から出てきた、何もしない関数。
指示はただ一つ、return 0というものだけ。main関数の結果として、0という数字を返すことを表している。
main関数はint(整数)の要素を返す、と書いてある(1行目)。0は当然整数なので問題なし。
このmain関数は始まったら即座に結果0を返して終了する。プログラムはmain関数から始まり、main関数が終わると終了する。したがってこのプログラムは始まったら即座に終了する。
ちなみに、main関数の結果として0を返すのは「問題なく終了した」ことを表す*2。ただし、絶対ではない。1を返しても別に問題ないことが多い。
関数の呼び出し
int putchar(char c);
char f(char c) { return c; }
int main() { putchar(f('a')); return 0; }
上のプログラムを動かすと、画面にアルファベットのaが表示されて終了する。
流れは次のようになる。
- main関数が始まる。
- putchar関数の「引数」である関数f*3を実行する*4。
- fは引数として文字a('a')を受け取る。そしてそのまま返す。よってf関数を呼び出した箇所は文字aと同じ扱いになる。
- putchar関数が呼び出される。実体はプログラムに書かれていないが、内容は決まっていて、文字を表示するものである。
- 文字を出したら終了する。
ちなみに、1行目のint putchar(char c)は「putchar関数が引数として文字を1つとり、intを返す関数である」ことを表している。実体は書けないので関数の「宣言」だけである。
再帰単独
int f() { return f(); }
int main() { f(); return 0; }
上のプログラムは「終わらないプログラム」である。以上。
流れは次のとおり。
- main関数が始まる。
- 関数fを実行する。
- 関数fの中で関数fを実行する。
- 次の関数fの中で関数fを実行する。
- 以下無限に同じ文章。
ただし、このプログラムを実行すると多くのパソコン(+コンパイラ、処理系、コードをコンピュータの実行可能なファイルに変換するもの)では「エラーを出力して終了する」ことになる。
実際のところは、関数を実行するときには「いくつかの情報」を保存しなければならず、それが無限に増えていくためいつか保存しきれなくなって終了する、というのが現実。
「いくつかの情報」とは、たとえばその関数の中でだけ使える変数や引数(戻ってきた後実行を続けるのに必要)、関数を呼び出した場所(戻ってくるときに必要)といったところ*5。
条件分岐+include
#include<stdio.h>
int main() {
if(1 < 2) { puts("YES!"); }
else { puts("What?"); }
return 0;
}
上のプログラムは条件分岐を使ったもの。
1行目はstdio.hというファイルを読み込む命令。このファイルにはputchar関数の宣言のほかにもputs関数という関数の宣言なども入っている。
流れは以下のとおり。
- main関数が始まる。
- ifという語で条件分岐が行われる。1 < 2か?という当然正しいことを条件としている。
- 条件が正しいので直後にある命令を実行する。内容はputs関数をYES!という「文字列」を引数にして呼び出す、というもの。
- puts関数が実行され、引数であるYES!という文字列が画面に表示される。
- elseというのはifの条件が正しくない場合に実行されるものなので、今回の場合その直後の命令は無視する。
- 0を返してmain関数が終了する。
以上である。なお、elseのほうは省略してもよい。省略した場合、ifの条件が正しくなかったら何もしない。
まとめ
概要をご覧ください(笑)。
復習のためにある程度のコードを見せ、その説明をした。
次回予告
「繰り返し」について今度こそ説明する。
簡単に言えば、「条件が正しい限り何度も実行する」もの。
3種類ほどあるのだが、この解説では1つしか説明する気はない。
最後に
この方式は変わりそうもないので、あきらめて最後まで書いて、そこから修正するか。
いっそ全体を説明することにすると、残りは組み込み型残り、gotoとラベル、条件分岐や繰り返しの残り、ポインター、構造体と共用体、型の修飾子や別名宣言、マクロなど。
うーん・・・あと10回くらい?
*1:C言語の仕様だけでは絶対に必要。ただし、組み込みなどの一部では関数を使わなくてもできる場合もあるはず。
*2:厳密にはEXIT_SUCCESSという「マクロ」を返すのが正しい。しかし、マクロの説明をしていないのでここでは却下。
*3:なぜかf関数とは言わないことが多い。関数mainは言うことも多いが、最初にmain関数と呼んでしまったのでmain関数に統一。
*4:実行順序について説明していないが、C言語の場合引数が先。
*5:多くのパソコンでは、という言い方からわかる人もいるかもしれないが、終了しないこともある。関数fの実行が常にreturn命令の中で書かれており、かつほかに実行する内容がないため、保存しておいた情報を全て破棄しても問題ない。そのため情報が蓄積されず、終了しなくなる。末尾呼び出し最適化と呼ばれる。