昨日は、btreesort を作るのに main.c と btree.c の 2つのファイルに分割した。main.c では btree.c の中で定義している BTreeSort() 関数を使うために、関数プロトタイプを記述した。
さて、例えばプログラムがもっと大規模になって、ソースファイルの数も増えるとしよう。BTreeSort() 関数もいくつかのソースファイルから使うようになるかもしれない。そうした場合、そのいくつかのソースファイル全てに関数プロトタイプを記述するのは効率が悪い。また、間違いのもとでもある。今回の例では関数ひとつしかないけど、一般的に考えればもっと多くの関数があるかもしれないし、構造体などの定義も必要かもしれない。そうなると、関数や構造体を使用するソースファイル全てに間違いなく記述するのは困難になってくる。
それを解決するのがヘッダファイル(*.h ファイル)だ。外部に公開したい関数のプロトタイプなどはヘッダファイルに記述しておき、それを使いたいソースファイルではそのヘッダファイルをインクルードすればいい。
早速やってみよう。今回の例では、btree.h というファイル名になる。
void BTreeSort(int ary[], const int n);
公開したい関数がひとつしかないので、ヘッダファイル(btree.h)もその関数プロトタイプだけだ。
一般的には、次のようなものをヘッダファイルに記述する。
- 外部に公開するマクロの定義(関数型マクロの定義)
- 外部に公開する定数の定義(#define や enum による定義)
- 外部に公開する構造体、共用体の定義
- 外部に公開する型の定義(typedef による型の定義)
- グローバル関数のプロトタイプ宣言
- グローバル変数の extern 宣言
5つ目のが今回の場合に当たる。
で、ソースファイル(main.c、btree.c)の方では、次のように btree.h をインクルードする。
#include #include #include #include "btree.h" #define MAX 10 void PrintArray(int ary[]); int main(void) { int i; int ary[MAX]; srand((unsigned)time(NULL)); for (i = 0; i < MAX; i++) { ary[i] = rand() % 100; } printf("unsorted: "); PrintArray(ary); BTreeSort(ary, MAX); printf("sorted: "); PrintArray(ary); return 0; } void PrintArray(int ary[]) { int i; for (i = 0; i < MAX; i++) { printf("%2d ", ary[i]); } printf("\n"); }
#include #include "btree.h" typedef struct tree { int value; struct tree *left; struct tree *right; } Tree; Tree *Insert(Tree *root, int val); int Traverse(Tree *root, int ary[], int n); void FreeTree(Tree *root); void BTreeSort(int ary[], const int n) { int i; Tree *root = NULL; for (i = 0; i < n; i++) { root = Insert(root, ary[i]); } Traverse(root, ary, 0); FreeTree(root); } Tree *Insert(Tree *root, int val) { if (root == NULL) { root = (Tree *)malloc(sizeof(Tree)); root->value = val; root->left = NULL; root->right = NULL; } else { if (val < root->value) { root->left = Insert(root->left, val); } else { root->right = Insert(root->right, val); } } return root; } int Traverse(Tree *root, int ary[], int n) { if (root->left != NULL) { n = Traverse(root->left, ary, n); } ary[n++] = root->value; if (root->right != NULL) { n = Traverse(root->right, ary, n); } return n; } void FreeTree(Tree *root) { if (root == NULL) { return; } else { FreeTree(root->left); FreeTree(root->right); free(root); return; } }
うまくコンパイルできるかな?
takatoh@nightschool $ ls btree.c btree.h main.c takatoh@nightschool $ gcc -Wall main.c -c takatoh@nightschool $ gcc -Wall btree.c -c takatoh@nightschool $ ls btree.c btree.h btree.o main.c main.o takatoh@nightschool $ gcc main.o btree.o -o btreesort takatoh@nightschool $ ls btree.c btree.h btree.o btreesort main.c main.o takatoh@nightschool $ ./btreesort unsorted: 89 46 78 22 0 23 82 86 84 64 sorted: 0 22 23 46 64 78 82 84 86 89
出来た。