二月二四日、日曜日の話
C言語ーー!!

 プログラム作ってると、だんだん眠くなってきます。

[◆]よっしゃー!!

 現在、C言語でプログラムを作っているわけだがこれがなかなかうまく行かない。まー、当たり前と言えば当たり前なのかもしれないけれども。

−−−−− ここから省略可能 −−−−−

 C言語は古参のプログラムであり、仕様として実は結構難しくも柔軟なプログラムである。使いこなせれば相当洗練されたアプリケーションが作れることは間違いない。ただ、使いこなすまでが相当大変であることはやってみればわかる。Visual Basic や Delphi とはかなり違うね。

 最初に分かる大きな違いといえば、文字を取り扱うデータ型の使用方法である。C言語は文字を規定してはあっても、文字列を取り扱うデータ型はない。一文字一文字、配列と呼ばれる並んだ箱に入れていき、一つ一つ読んでは一つ一つ入れていかなくてはならない。ま、それにあわせて文字配列を文字列のように取り扱う関数があったりするのだが、わりーと扱いにくかったりする。

 特に文字配列の扱いにおいて躓くのが「ポインタ」という概念であり、データ型ではなくメモリアドレスを参照してうんたらかんたらと僕もなかなか理解しにくい。理解できていたらおそらくは何の問題もなくプログラムを組めるのだろう。分かってないから問題がいつまで経っても解決しない。

 この土日をかけて勉強を重ねて作った文字列編集関数がある。おそらくは誰もが作ってる関数だ。プログラム界で言うところの Trim 関数というもので、通常の Trim 関数は指定された文字列の両側にスペースが入っていたらそれを取り除く機能を持つ(" space "を"space"にする)。これを少々改良して、取り除く文字を指定できるような形にしたかった。通常はスペースだけのところを消したい文字を指定してそれを削除するような機能を持たせたかった。そうしたところであまり使いどころがないかもしれないが一応。実は必要があるからそうしたかったんだけれども、僕が使いたい場面以外で使いどころが思いつかんな。

 この関数を作るのにかなり苦労した。ネットからすでに作られた関数を参照し、どのような仕組みで動いているのかをデバッグ用関数を入れつつ調べまわり、教本に載ってない関数が使われているときには調べ、いざわかったと思って自分で作った関数に組み込んでアプリケーションにしようと思ったらエラーが出てその理由が理解できない。プログラムの書かれたテキストファイル(ソースという)をアプリケーションにする(コンパイルという)コンパイラーは少し中級者向けのコンパイルしてくれるだけのプログラムであり、コンパイルできなかったら問題のある行と理由を表示してくれるが理由の説明が「パラメーター'__dest'は signed char * 型と指定されており、 int は渡せない」とか言われて「どこでその変数を int なんかに変換したよ?」と首を傾げてしまう。分かる人なら「君がそういう記述をしているからだろ」と言うのだろうが、どこで記述したことになっているのかが分からない。困った。

 ネットで検索すれば僕のほしい関数がぽいっと書かれていたりするのだが、なんかそれでは味気ない。今作っているプログラムは僕の人生を左右させるぐらいのプログラムである。他人が作ったプログラムを丸投げなんてしたくない。というより、自分が理解していないものをそのまま使いたくない。いざというときに動けるのは僕一人しかいないわけで、問題が発生して「原因が分かりません」では弾が全弾補充されているリボルバー式拳銃でロシアンルーレットをしているようなものだ。乗っかった時点で死ぬことが決定されている。

 急がなくてはならないが、動けばそれでいいなんて絶対に許されない。分からないならば、分かるまで時間をかけて勉強するしかないのである。

−−−−− ここまで省略可能 −−−−−

 そういうわけで、必死にプログラム作っていたわけであるが、途中はさんさんたるものだった。何とかコンパイルできて起動してみたらいつまで経ってもプログラムが終了しない。関数がひとつしかない状態の癖にCPUの能力を半分も使っている。なんだろうとデバッグ文字を出力することにした。関数の始まりにA、途中にB、終わりにC。これでどこまでプログラムが処理されているかを判断できる。あ、途中にループがあるのでループ内にもDをおいておこう。

 結果

 無限ループって怖くね?

 どうやら、ループを終了させるための判断式が間違ってるらしい。そのためにいつまで経ってもループが終わらずに永久ループに陥っているわけだ。残念。で、正しい判断式はどう書けばいいんだろう……。strcmp じゃだめか、処理対象文字列の最初の一文字と削除文字を比べようとしたのだが、これじゃあ処理対象文字列全体と削除文字を比較してしまっている。文字列 対 文字ではそりゃいつまで経っても一致しないだろうね。

 それで試行錯誤を繰り返し、ようやく処理対象文字列の最初の一文字と削除文字を比較する方法を見つけた。思った以上に簡単な式だった……。ポインタだなぁ……。

参考:最初に書いていた判断式行 while ( strcmp( str, delstr ) != 0 ) str++;
参考:正解の判断式行      while ( *str == *delstr ) str++;

 それはそうとしても、処理が正しく終了したとき思わず「よっしゃー!」と立ち上がって叫び、今まで苦労していた過去の僕に向かって「俺はやったぞー!」と盛大に飛び上がって見せたね。端から見れば明後日に向かって万歳している男がいるってことになるんだろうけれども。その時、妹が隣の部屋にいなくて良かったと思う。

 とりあえず、ポインタの加算、減算についても少しわかった感じだ。アドレス番号が移動するのね。なるほど。

 今回作った関数は str 文字列の左側に delstr があればつめていくという処理だった(見た目には削除するように見えるのだが、実際には詰めるというほうが正しいだろう)。今度は右側に delstr があればつめていく処理をし、その二つを組み合わせて両側に delstr があればそれぞれ詰めて完成である。長かった。

 さて、次はカンマで区切られたデータを分割する関数を作りたいのだが……その前にゲームしたいなぁ。ああでも今からゲームなんかしたらまた午前一時になってしまう。寝る時間が……。