構造体と記号定数の定義
構造体のリンクには一方向(片方向)と双方向がありました。このプログラムでは、コマンドラインに入力された順に先頭からファイルを処理するだけなので、一方向のリンクで対処できます。
構造体の定義
構造体のメンバに『次の構造体』を示すポインタ(自分自身の型のポインタ)を組み込み、リンクの最後にはそこへNULLを代入する――という形です。図1のようなイメージになります。
構造体"_CONV"には、これまでのメンバに加えて『次の構造体』を示すポインタを設定します。その場合、これまでのように宣言時に構造体タグを省略する方法は使えません(リスト1)。メンバを定義する{}の中では、まだ自分自身を示す名前が定義されていないためです。
構造体をポインタでリンクする場合には、structに続けて構造体タグを定義し、そのタグを使って自分自身へのポインタをメンバに設定します(リスト2)。
リスト1:構造体タグを定義しないと自分と同じ型へのポインタをメンバに設定できない
typedef struct {
int tab; /* タブストップ幅 */
char fname[256 + 1]; /* 入力ファイル名 */
FILE *fp; /* ファイルポインタ */
} _CONV;
リスト2:タグを定義して自分自身へのポインタをメンバに設定する
typedef struct __conv {
int tab; /* タブストップ幅 */
char fname[256 + 1]; /* 入力ファイル名 */
FILE *fp; /* ファイルポインタ */
struct __conv *next; /* 次の構造体へのポインタ */
↑タグを使ってポインタを設定する
} _CONV;
記号定数の定義
以降、main関数をまず紹介し、そこから呼び出される関数を紹介していきます。
その前に記号定数を定義しておきましょう。リスト2のようになります。
入力ファイル名のサイズは256バイトとし、"NAMESIZE"という記号定数を充てておきます。入力ファイルにはソースファイルを前提としているので、実際にはこれほど長い名前を使うことはないでしょう。
この256バイトという設定はパス名も含めたサイズとなりますが、プログラミングではソースファイルは1つのフォルダに固めることが一般的で、せいぜいヘッダファイルをincludeやheaderといったフォルダに分類する程度です。そのため、あまり長くしても意味がありません。
先に定義した構造体_CONVは、この記号定数NAMESIZEを使って、リスト4のように書き換えることができます。
リスト3:記号定数の定義
#define ARGMIN 2 /* オプションの最小数
これ未満はエラーとする */
#define BUFSIZE 1024 /* 文字列処理バッファのサイズ */
#define NAMESIZE 256 /* ファイル名のサイズ */
#define DEFAULT_TAB 8 /* 標準のタブストップ */
#define MIN_TAB 2 /* 最小のタブストップ */
#define MAX_TAB 16 /* 最大のタブストップ */
#define SPACE 0x20 /* スペースコード */
#define TAB 0x09 /* タブコード */
#define _FF 0x0c /* 改ページコード */
#define BOOL int
#define TRUE 1 /* 論理値--真 */
#define FALSE 0 /* 論理値--偽 */
#define ERR (-1) /* シェルに返すエラーコード */
リスト4:記号定数を使って書き直した構造体の定義
typedef struct __conv {
int tab; /* タブストップ幅 */
char fname[NAMESIZE + 1]; /* 入力ファイル名 */
FILE *fp; /* ファイルポインタ */
struct __conv *next; /* 次の構造体へのポインタ */
} _CONV;
|