処理に名前を付けて部品化する。コールスタックの舞台裏、変数の見える範囲と寿命、そして再帰の入口まで。
朝の支度を人に説明するとき、「歯ブラシを取って、水を出して、みがいて、口をすすいで……」と毎回すべてを言う人はいません。ふつうは「歯をみがく」の一言で済ませます。手順のかたまりに名前を付けたからです。 プログラムでも同じことをします。処理のかたまりに名前を付けて、いつでも呼び出せる部品にしたもの。それが関数です。ここまで毎回書いてきた main も、実は関数…
自動販売機を思い浮かべてください。お金を入れる(渡す)と、ジュースが出てくる(返る)。関数もこれと同じで、入口と出口を持てます。入口が引数、出口が戻り値です。 int add(int a, int b) の読み方はこうです。先頭の int が「この関数は int を返す」、カッコの中が「int をふたつ受け取り、関数の中では a と b という名前で使う」。…
Cのコンパイラは、ソースコードを上から順に一度だけ読みます。まだ見たことのない関数がいきなり呼ばれると、「そんな名前は知りません」と怒って止まります。そこで先に名刺だけ渡しておくのがプロトタイプ宣言です。 プロトタイプ宣言は、関数の名前・戻り値の型・引数の型だけを伝えて、セミコロンで終わります。中身({ })は書きません。これがあるおかげで、main を先頭…
学校のクラスでしか通じないあだ名があります。教室の中では誰にでも通じるのに、一歩出ると誰も知らない。変数にもこれとまったく同じ性質があり、名前が通じる範囲のことをスコープと呼びます。 Cのスコープの単位はブロック、つまり { } です。ブロックの中で宣言した変数は、その } に到達した瞬間に消えます。 同じ n という名前でも、別の関数のものはまったく別の変…
前のトピックが「どこから見えるか」の話なら、今回は「いつまで生きているか」の話です。この2つは似ていますが別物で、混ぜて考えると必ずつまずきます。 ふつうの局所変数は自動変数と呼ばれ、宣言された瞬間に生まれ、ブロックを抜けると消えます。関数を呼ぶたびに新品が用意されるので、前回の値は残っていません。使い捨てのメモ用紙のようなものです。 ところが、関数の中に置…
関数を呼ぶと、なぜ元の場所に戻ってこられるのでしょうか。しかも、呼ばれた側のローカル変数はどこに置かれているのでしょうか。その舞台裏がコールスタックです。 食堂のお盆を想像してください。新しいお盆は必ずいちばん上に積み、取るときもいちばん上から取ります。関数の呼び出しもこれと同じ規則で動きます。 関数を呼ぶ → その関数専用の作業台(スタックフレーム)を積む…
このトピックは、第2部のポインタへ続く最重要の伏線です。ここを曖昧にしたままポインタに進むと、必ず迷子になります。 Cの関数に値を渡すと、渡るのは原本ではなくコピーです。書類の原本を手渡すのではなく、コピー機で複製を取って渡すイメージ。これを値渡しと呼びます。 add_ten の中の n と main の n は、名前が同じでも別の箱です。前のトピックのコー…
関数の外側、ファイルの先頭で宣言した変数は、そのファイルのどの関数からも見えます。これがグローバル変数です。家中の誰でも触れる、廊下に置かれた共有の棚だと思ってください。 引数も戻り値もなしに値を共有できるので、一見すると便利です。寿命はプログラムの開始から終了までで、初期値を書かなければ 0 に初期化されます(static 局所変数と同じ性質です)。 なぜ…
文法を覚えた次は、「どこで切るか」という設計の話です。判断の軸はひとつ、1つの関数は1つの仕事。これだけ守れば、たいていうまくいきます。 分割前のコードを見てください。 やっていることは「合計」「最高点」「表示」の3つです。名前を付けて分けます。 行数はむしろ増えました。それでも読みやすくなったと感じるはずです。main が「何をしているか」の一覧になり、細…
合わせ鏡をのぞくと、鏡の中にまた鏡が映り、その中にもまた鏡が映ります。関数も同じことができます。自分自身を呼び出す関数、それが再帰です。 教科書的な題材は階乗です。5の階乗は 5×4×3×2×1 ですが、これは「5 × 4の階乗」と言い換えられます。同じ形の、少しだけ小さい問題が中に隠れている——この構造が見えたら再帰の出番です。 再帰に必要な部品は必ずこの…
もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。