STEP 8 - 定義関数 │ ├ 定義関数を作成する基本手順 ├ プロトタイプ宣言 ├ 引数を持つ定義関数 ├ 定義関数の基本的な記述 ├ 戻り値を持つ定義関数 ├ 再帰的な関数の呼び出し ├ 関数のポインタ呼び出し └ 関数のポインタ配列 └ ヘッダファイルの作成 |
Written by Yuki. http://ftc.suki.net/ |
定義関数とは VBの自作関数の様なもの。定義関数もサブルーチンという。
<定義関数を作成する基本手順> #include <stdio.h> void func1(void); ' func1という定義関数の存在を宣言する。書かないと作った関数は使えない。 void main() こういったプロトタイプ宣言は行末にセミコロンを付ける。 { func1(); ' 定義関数を呼び出す。 } void func1(void) ' "戻り値 関数名(引数)" で定義関数の定義になる。 { 戻り値が無ければ voidを指定。省略すると int型になる。 printf("こんにちは"); return; ' 定義関数の終わりを示す。 } ' これで "こんにちは" と表示する定義関数となる。 これでメインで呼ばれた定義関数で "こんにちは" と出力されるプログラムになる。 関数名の規則は変数名と同じで、標準関数と重複してはならない。関数名は大文字と小文字を区別する。 また、引数がなければ voidを指定する。
<プロトタイプ宣言> ビルド(コンパイル)する時に、コンピュータにプロトタイプ宣言で 記述された定義関数が存在する事を知らせる。 #include <stdio.h> void func1(void); ' 定義関数の存在を知らせる。宣言時はセミコロンを付ける。
<引数を持つ定義関数> void func1(int a) ' 引数の型・定義関数内部で引数を格納する変数。 { printf("%d\n",a); return; } ・引数は 1つだけでなく、必要ならば複数定義できる。 void func2(int a,int b); void func3(char *cp,int a);
<定義関数の基本的な記述> 戻り値の値 関数名(引数1の型 引数1,引数2の型 引数2,……) ' void func1(int a,int b) { 戻り値なしなら↑ ↑引数なしなら void 関数で行う処理1; 関数で行う処理2; return; } ・配列を引数にする時はポインタで指定する(文字列を引数にする時)。 void func1(int a,char *b); ' プロトタイプ宣言でもアスタリスクを付けておく。 ' メインで呼び出す時は、配列名のみを記述する。
<戻り値を持つ定義関数> #include <stdio.h> int max2(int,int); void main() { int i; i=max2(3,4); ' max2に値を代入する。その後、iにmax2の持つ値が入る。 printf("%d\n",i); } int max2(int a,nit b) ' 戻り値の型を指定。 { if(a>=b) ' 値を判定。 return(a); return(b); ' max2は 2つの引数のうち大きい値を返す。 } 定義関数自体が bという値を持っている。 ・printfで定義関数を指定すると、その関数の持つ値が出力される。 printf("%d\n",max2(2,5)); ' 実行されると戻り値の数値に置き換えられる。 上のプログラムで考えると、戻り値の 5に置き換えられる。 ※returnは関数の終わりではなく、mainに戻るという意味である。 return(戻り値); return(1); ' 戻り値は 1。 return(a); ' 戻り値は aの格納している値。 return(a+1); ' aの格納している値+1。 ※returnはメインルーチンに戻る命令であり、同時に戻り値を指定する命令である。 サブルーチンが型を持っている場合は、returnの後に括弧を付けて戻り値を指定する。 だから、サブルーチンの型が voidの時には何も付かない事になる。 但し、関数の戻り値は一つしか指定できない。 int max2(int a,nit b) { if(a>=b){ return(a); ' returnがあると呼び出された所へ戻る。 }else{ その結果必然的に戻り値は一つになる。 return(b); ' elseならば、こちらの returnで、bの値が戻り } これ以下の文は実行されない。 }
<再帰的な関数の呼び出し> #include <stdio.h> void recurse(int); void main() { recurse(0); ' メインから関数の呼び出し。recurseは再帰の意味。 } void recurse(int i); ' 実際には関数の開始地点のアドレスを呼び出している。 { そのアドレスの番号順に処理を行う。 if(i<3){ ' 呼び出しの際に 0を指定する事で iに 0が代入される。 recurse(i+1); ' 関数内でまたその関数を呼ぶ。これが再帰である。 printf("%d\n",i); } return; } @:メインから引数 0で呼び出される。 A:再帰して引数 1で呼び出される。 B:再帰して引数 2で呼び出される。 C:再帰して引数 3で呼び出される。 if文を実行せずに呼び出された場所へ戻る。この時Bへ戻る。 D:Bで呼び出しているので 2を表示。この後Aへ戻る。 E:Aで呼び出しているので 1を表示。@へ戻る。 F:@で呼び出しているので 0を表示。そして、メインへ戻る。 再帰では、それまでに繰り返してきた処理を、最後から順に出力していく。 最終的にはメインに戻り、処理が終了する。しかし実際にはこの方法は滅多に使わない。
<関数のポインタ呼び出し> 関数はビルドにより、マシン語に翻訳されてメモリに格納されている。関数が呼び出される時は、 関数の先頭アドレスが呼び出される。そのアドレスを、ポインタ変数などを用いて管理する。 ↓括弧で括る。 戻り値の型 (*ポインタ変数名)(引数の型); ↑ポインタ変数に格納する ↑引数が複数の場合はカンマで区切る。 関数の戻り値の型。 (使用例) int型の引数を 2つ持ち、int型の戻り値を返す関数を格納するポインタ。 int (*p)(int,int); ※格納する関数の戻り値の型、引数と個数。これらは必ず一致していなくてはならない。 int func(int,int); p=func; ' 関数名のみを書く事により、その関数の先頭アドレスを表す。
<関数のポインタ配列> 考え方は変数を使用したポインタ配列と同じである。 戻り値の型 (*ポインタ変数名[要素数])(引数の型); (使用例) 戻り値の型と引数の型・個数が同じ関数が 3つあるケース。 int func1(int); int func2(int); int func3(int); ' 一つ一つがサブルーチン。 int (*p[3])(int)={func1,func2,func3}; ' 中括弧内のそれぞれが pの要素になる。 2つの数値の計算方法を指定する。 #include <stdio.h> int add(int,int); int sub(int,int); ' プロトタイプ宣言。 int (*p[2])(int,int)={add,sub} ' ポインタ配列に 2つのサブルーチン(の要素の型)。 void main() { int i,j,op,res; ' i,jは数値入力用、opはポインタ配列の添え字、 scanf("%d",&i); resはポインタ配列の戻り値を格納する為のもの。 scanf("%d",&j); do{ scanf("%d",&op); }while(op<0 || op>1); ' opに 0より下、又は 1より上が入力されている間、繰り返す。 res=(*p[op])(i,j); ' ポインタ配列の 0、又は 1に i,j の値を。 printf("%d\n",res); ' printfで resに入った戻り値を呼ぶ。 } int add(int a,int b) ' a=i,b=j { return(a+b); } ' 宣言の時点で addが 0、subが 1である。 ' opに 0が入れば、加算するサブルーチンを、 int sub(int a,int b) ' 1なら減算するサブルーチンを実行する。 { return(a-b); } ' 計算結果が戻り値として resに入り、出力される。 この様に、ポインタ配列でサブルーチンを管理する事で、 任意の計算方法を選択したり、処理の仕方の分岐等をさせる事ができる。 ※関数を配列にする時には、要素となる定義関数の引数は全て同じでなければならない。 上の例のように、addと subの引数が同じでない時、例えば要素の 1つが intでなかったり、 戻り値の型が違ったりするとエラーになる。 要素の型は、ポインタ配列の宣言の時に書かれた要素と同じである必要がある。 ・ヘッダファイルの作成 @:「ファイル」→「新規作成」の順にクリック。 A:一番上の「C/C++ヘッダファイル」の項目をクリック。ファイル名を付けて、OKを押す。 B:クラスの下に (ファイル名).h のヘッダファイルが作成される。 ヘッダファイルには定義関数等を記述しておく。
← ← Back to BeforeStep | Go to NextStep → → |