khurata’s blog

khurata’s blog

C による「文字指向」のファイル処理

(もともと「Yahoo!知恵袋」の「知恵ノート」だったものを転載しています)
(最終更新日時:2016/5/23)投稿日:2015/11/5

はじめに

 「C言語で/*~*/のようなコメントの数を数えるプログラム」 http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14152219699 という質問があり、回答を用意していたのですが、回答投稿前にベストアンサーが決定されてしまいました。

 せっかく書いた説明やサンプル・プログラムを埋もれさせるのももったいないですし、おそらくは C の初学者の方々にとって参考になるだろう、とも思いましたので、ここであらためて披露致します。

 

C の文字列は「配列」である

 C は、1バイト文字を処理する事は不得手ではありませんが、文字列を扱おうとすると、途端に面倒になります。

 そもそも C には文字列というデータ型を扱うための基本型が存在せず、「char 配列の要素のどこかに 0 を入れたもの」を文字列として扱う、という取り決めになっています。
 しかし、C の配列は、モダンなスクリプト言語に比べると、かなり原始的かつ不自由なものであるため、C で文字列を扱うのは面倒なのです。

 

「行」で処理することの問題点

 「テキストファイルを処理するプログラムを書く」ことは、プログラミングの良い練習になります。 特に C に関しては、「面倒な文字列」を処理する練習を積むことはとても重要です。

 さて、多くの人は、「C でテキストファイルを処理する」と聞くと、「改行までの文字列」、つまり「行」を単位として処理するプログラムのイメージを持たれることと思います。 

#define BUFSIZE 1000
ですとか、
#define LINE_MAX 500
みたいな、「行の文字数」を決定するマクロ定義を、C プログラマは何度も目にしたことがあるはずです。

 しかし、「行単位で処理する」プログラムは、C の場合、次のような問題がつきまといます。

a)1行の文字数が少ない場合、配列のメモリが無駄である。
b)処理対象の行が定義された最大文字数を超える場合、行数を正しく処理するのが面倒である(論理行と物理行の対応)。


 これは、C の文字列が「原始的で不自由な配列」であるために、仕方の無い問題として存在します。

 

「文字指向」と「状態遷移」

 「/*~*/ 形式のコメントを処理する」というのは、C プログラミングにおける古典的な「お題」の1つです。 こうした処理を実現するために、fgets() などを用いた「行指向」のプログラムを書くこともよくありますが、ここでは「1文字ずつ読み取って処理する」文字指向に、「状態遷移」を組み合わせたサンプルを作ってみました。
http://yahoo.jp/box/pGIf7E
(ダウンロードして使う際は拡張子 .txt を取り除いてください)

 

※ いつの間にか「Yahoo!ボックス」が共有サービスをやめてしまっていたため、下記にアップロードし直しました。 拡張子は .c になっていますのでそのままお使いください(2021/01/09)。

http://khurata.dyndns.dk/QA/q14152219699.zip

 

 これが、どのように動作するプログラムであるかは、コメントを見ながら読み解いていけると思います。 使い方は、Linux 端末においては次のようになります。

$ gcc q14152219699.c コンパイルする
$ cat q14152219699.c | a.out 標準入力からデータを与える

  このような「文字指向」プログラミングであれば、長大な配列を用意する必要も無く、任意の長さの行を処理することができるのです。

 

「文字指向」の欠点

 行は、文字の集まりなので、やろうと思えば、行指向のプログラムは全て文字指向で書き直すことも出来ます。 そう考えると、文字指向は「万能」ではないか、とも思えますが、文字指向には以下の欠点が有り、行指向を選択すべき場合も多々あります。

1)行指向に比べると処理速度が遅くなりやすい。
2)場合によっては「過去文字」や状態の管理が、かえって複雑になってしまう。

 

おわりに

 K&R などの教科書にも、ファイル処理は1文字ずつというサンプルは多数載っているのですが、行指向は、多くの場合において、便利で充分なアプローチなので、C に慣れてくると、文字指向のプログラミングを忘れがちになってしまう傾向がある、と私は思います。
 しかし、「行指向だと、どうもしっくり来ないなぁ…」という場合、文字指向は有力なアプローチに成り得ます。 たまには「1文字ずつ」処理することも、思い出してみてはいかがでしょうか。
(転載以上)