このプログラム(の部分)は一見間違いに見えるかも知れないが,きちんと動く.ちなみに,図中の番号は異なるiを指し,同じ番号で指されているものは同じiを表す.
筆者は卒業研究で,これが何重にも重なったプログラムを扱わなければならない事があったが,非常に見づらく,処理プログラムを作成しなければならない程であった.これは”ちょっと使わせてもらおう”的な発想によるものであろうが,使用はお勧めできない. いずれの場合にしろ,使用前に宣言すると言うことが,大事である.
では,ここで話を関数の宣言に戻そう.関数をどこで宣言するかということは,その関数をどの範囲で使用するか,と言うことによって決まる.つまり変数の宣言と同じで,関数の外で宣言すれば,それ以降の関数で全て呼び出すことが出来る.ある関数内で宣言すれば,その関数からしか呼ぶことが出来ない.また,{ }内で囲んだところで宣言してしまえば,その中でしか呼ぶことが出来ない(但し,コンパイラによっては呼び出すことができる).結局,関数の宣言位置も変数の宣言位置と同様に,
関数の宣言−1)関数内で宣言する.
→その関数内でしか呼び出すことが出来ない.
関数の宣言−2)関数の外で宣言する.
→その宣言以降の関数全てから呼び出すことが出来る.
関数の宣言−3){ }内で宣言する.
→{ }内でしか呼び出すことが出来ない.
という事が言える.
関数が必ず{ }でくくられていることを考慮すれば,1)も3)も同じ事を言っている. |
では,グローバル変数やほとんどの関数を全て一番上で宣言すればいいかというと,そうでもない.確かにそうすれば,どの関数からも呼び出す(参照する)ことが可能であるが,これは余りいいことではない.出来れば,関係ない関数からは呼び出せない(参照出来ない)ようにしておいた方がよい.やたらと必要ないところから,呼び出せるようにしておくのは,得策ではない.関数を作成する際には,ここの関数間の独立性を高め,必要な関係だけ結ぶようにしておくことが重要である.例えば,先のex-2.においてstackとposは一番上ではなく,popとpushの直前においておくことが望ましい.この二つの変数は,この二つの関数からしか参照しないためであり,他の関数から参照する必要性は一切起こり得ないからである.(もし起こり得た場合は,アルゴリズムを考え直した方が良い)
関数の定義部(本体)は,ファイル内のどこにあってもよい.同じファイルでなくてもインクルードファイルの中にあればそれでよい(後述する).要は,使用する前に宣言しておけば良いのである.
さて,関数の宣言が定義されると,使用する関数を事前に宣言しておかなければならなくなった.しかし,いちいち
int printf(………………………………); /*驚いてはいけない.printfも */
int scanf(………………………………); /*scanfも ちゃんと返り値がある*/
char getchar();
などと宣言するのは面倒であり,既に多く用意されている関数を,(宣言するために)全て覚えるのも大変である.(事実我々はこの様な宣言を行わずに,これらの関数を用いている)
そこで,システムが予め用意した関数はユーザがいちいち宣言しなくてもすむように,ヘッダファイルというものにまとめて宣言されている.ヘッダファイルは通常,拡張子がhのもので,既に学んだもので stdio.h,stdlib.h,ctype.h,math.h などがある(詳しくは各書籍を参考されたい).これらのファイルには,その名前が示し通りも関数が宣言されている.例えば,
stdio.h → Standard I/O : 標準入出力関数群
printf, scanf, getchar, putcharなどの関数とEOF.
stdlib.h → Standard Library : 標準ライブラリ群
atoi, itoaなど.(まだ,解説していない)
ctype.h → Character Type : 文字操作関数群
isalpha, isdigit, tolower, toupperなど.
string.h → String : 文字列操作関数
strlen, strcat, strcpyなど.
math.c → Mathmaticals : 数学用関数群
sin, cos, log, sqrtなど.
などである.これらのヘッダファイルは通常ファイルの先頭で
#include <stdio.h>
として,その使用を宣言される.
では,具体的にどのようなことが行われているのか解説しよう.
Cでは#で始まる行はすべてプリプロセッサ(Preprocessor:前処理系とも言う))というものが処理する.つまりソースプログラムの#includeや#defineなどをコンパイラに通す前に処理する(プリプロセッサが処理するものについてはここでは言及しない.詳しくは各書籍を参考にされよ).
#includeも#defineも処理自体は簡単で,
#include → ヘッダファイルをその位置に張り付ける.
#define → 定義された文字列を,元の文字列に書き直す.
という事だけである.
つまり,先頭に#include<stdio.h>と宣言すると,その位置に(つまり先頭に)stdio.hの内容が全てコピーされる(たった一つの関数しか使わなくても).そうしておけば,以降の関数では全て,stdio.h内の関数を全て呼び出すことが出来る.
#defineは
#define MAX 100
と書いてあれば,ソースプログラム内の,MAXを全て100に書き換えるだけである.
|
さて,話が少しそれるが,このようなヘッダファイルは,システムが用意するだけでなく,ユーザの方で自由に作っておくことが出来る.今まで作った関数を,mylab.hなどのファイルに取っておき,それを#include "mylab.h"と宣言すれば,その中ある関数は新しいプログラムで自由に使うことが出来るようになる.(#include <>と#include ""の違いは後で述べる.)
筆者は永年,Cを使っているので個人で作成したヘッダファイルが4つほどある.以下にその一つ,base.hを載せるので参考にされたい.