Cogito Ergo Sum.

我思う故に我あり

Cの壁・ポインタ

 プログラミング言語Cの壁と言えば、悪名高い「ポインタ」をおいて他にないだろう。本屋のC言語関連コーナーに行けば、『絶対わかるポインタ』『ポインタ完全制覇』『ポインタから始めるC言語』なんてタイトルの本がワンサカある(最後のはないかもしれないが…)。

 僕自身は幸か不幸かCプログラマではなかったので、こういった本を多少冷ややかな視線で眺めていた。そんなにCプログラマを悩ませるものがあるんだとしたら、それはC言語の欠陥ではないのか?と思っていたからだ。そんなに苦労してまで克服しなければならない「壁」なんだろうか?

 僕はBASIC育ちの人間で、今でも思うのは、やはりBASICは文字列処理がもの凄く簡単だ、ということだ。C++JAVAのような現代的なプログラミング言語でも、80年代前半の行番号付きBASICの文字列処理の簡便さには遠く及ばないと思う。「文字列処理が簡単」というBASICの特徴は、現在のVisual BASICなんかにも微妙に引き継がれているように思う。これはBASIC文化なのだろう。

 僕がC言語の勉強を始めると最初に面倒臭く思うのが、決まってこの文字列処理だった。C言語で文字列を扱おうとすると文字型の配列の処理になるし(文字列の配列を扱おうとすると「配列の配列」になるし…)、それを簡潔に記述しようとするとポインタを扱うことになる。2つの文字列を連結するだけで、関数を呼び出さなければならなかったりする。そもそも、「何かって言うとすぐ関数を使う」というC言語文化に馴染んでいない僕には、もの凄く面倒だった。

 最近C言語の基礎の基礎の入門書を読み直していて、ちょっとポインタの印象がかわってきた。僕がプログラミングにおいて最も注意を向けているのはおそらく「処理の流れ」だろうと思う(「処理の流れ」と言うか「処理の順序(の制御)」と言うか)。これが数年前から「自分はもっと『データの流れ』に注目した方がいいのではないか」と思うようになっていた。それと言うのも、考えてみると、僕のプログラムではデータは関数間を流れていくものではなく、徐々に置き換わっていくものだからである(グローバル変数がいろんなところから順不同に書き換えられていくイメージ)。何故こういうことになってしまうかと言えば、プログラムが関数の組み合わせとして書かれていないからだ。僕が「データの流れ」の重要性に気づき始めてきたのは、「プログラムを関数の組み合わせとして書いた方がいろいろ楽だ」ということにようやく気づいてきた、ということなのだろう。僕が自分はいまだ古典的なC言語から学ぶことはたくさんあるだろうと思っているのは、こういう「プログラミングの基本中の基本」みたいなものが案外自分には身についていないことを知っているからである。

 プログラムを関数の組み合わせとして考えると、変数は関数と関数をつなぐ「窓」のようなものに見えてくる(その窓を通して、データをやりとりする)。その窓が単純な基本データ型だけだと大変なので、自然に構造体を使いたくなってくる(僕が全く構造体を使わないのは、データを関数間で受け渡ししないからだと思う)。構造体の配列を貰って処理する関数を考えると、ポインタを使って処理するのが最も簡単そうだ。単に「簡潔に記述できる」というより、「そう書くのが自然」という気すらする。と言うわけで、ポインタが「単に面倒なもの」には見えなくなってきた。

 (ちなみに、「関数に構造体を渡す」という発想からほんのちょっとだけ歩を進めれば「関数にオブジェクトを渡す」というのがこれまた当然の発想のように思えてくる。そういう意味でも、やはり僕みたいなタイプの人間は、オブジェクト指向プログラミングを学ぶ前にC言語を学んでおくことに意味があるんじゃないかと思う。)

 僕は昔、C言語ができないというコンプレックスからアセンブラの勉強を始めたことがある(入門書を数冊読んだだけだが)。もちろんアセンブラのプログラムが書けるようになったわけではないが、そのときにCPUの動作原理(と言うか、要するにコンピュータっていったい何をやっているのか)の大まかなイメージが掴めたのはもの凄く大きかったと思っている(それと別の本で得ていた、OS(MS-DOSですが…)の役割と仕組みについての大まかなイメージ)。おそらく、Cの壁・ポインタが単に厄介な落とし穴なのではなくて、Cプログラマにとって乗り越えるべき壁であるのは、ポインタについて勉強することによって、自分が操作しようとしているコンピュータのハードウェアの姿が見えてくるようになるからだろう。高級言語では多かれ少なかれ抽象化されているハードウェアだが、(そして、ハードウェアの生の姿なんか知らずにプログラムが書ければそれが一番かもしれないが)ハードウェアについて全く知らずに上手なプログラムを書くことも実際のところ難しい。アセンブラまでさかのぼらなくても、ポインタの学習をすれば、変数というものが要するに特定のメモリアドレスに名前をつけたものであることや、CPUにとっては特定のメモリアドレスが保持している値もメモリアドレスそのものも2進数の数値に過ぎないこと、その2進数にどういう意味を与えどう扱うかを決めることがプログラミングなんだということが見えてくる。それがCの壁・ポインタを学ぶことの意義なんだろう。