440 likes | 645 Views
関数の作りかた. 第7章. リスト 2数の平均値を求めるプログラム. #include <stdio.h> double ave(double x, double y); ー関数プロトタイプ int main(void) { double a, b, avdt; a = 11.11; b = 33.33; avdt = ave(a, b); ー関数ave()を使って平均を求める printf(“a=%df b=%f 平均=%f<br>”, a, b, avdt); return 0; }.
E N D
関数の作りかた 第7章
リスト 2数の平均値を求めるプログラム #include <stdio.h> double ave(double x, double y); ー関数プロトタイプ int main(void) { double a, b, avdt; a = 11.11; b = 33.33; avdt = ave(a, b); ー関数ave()を使って平均を求める printf(“a=%df b=%f 平均=%f\n”, a, b, avdt); return 0; }
double ave(doub le x, double y) ー関数ave()の本体 { double wk; ー関数ave()の中だけで一時的に使用する変数 wk = (x + y) / 2.0; ー渡された2数x,yの平均を求めwkに代入する return wk; ーwkの値を戻り値にする } 実行結果 a=11.110000 b=33.330000 平均=22.220000
図7-1 関数呼び出しの関係図 main()側 ave()側 a,b avdt=ave(a,b); 2数の平均 答え avdt = ave(a, b); a,bの値をx,yに渡す double ave(double x, double y) { double wk; wk = (x + y) / 2.0; return wk; } その和を計算する 答えを返す
リスト 複数rerurn文と処理打ち切りreturn文の例リスト 複数rerurn文と処理打ち切りreturn文の例 #include <stdio.h> #include <math.h> /* for sqrt() */ double maxdt(double a, double b); void disp_sqrt(double n); int main(void) { double mx; mx = maxdt(11.22, 33.44); ー最大値を求める printf(“mx=%f\n”, mx); disp_sqrt(2.0); ー平方根を表示 disp_sqrt(-5.0); ー負値の引数で呼ぶ return 0; } 関数プロトタイプ
/* 大きい値を返す */ • double maxdt(double a, double b) ー戻りの値の型はdouble • { • if (a > b) • return a; • else • return b; • } どれかのreturn文に出会うと値を返し処理を終了する
/* nが正の値なら平方根を表示する */ • void disp_sqrt(double n) ー戻りの値がないのでvoid型に する • { • if (n <= 0.0) return; ー処理打ち切りのreturn文 • printf(“%f の平方根=%f\n”, n, sqrt(n)); • }
実行結果 • mx=33.440000 • 2.000000 の平方根=1.414214 • ←disp_sqrt(-5.0)の対応表示はない
リスト void型関数の記述例 #include <stdio.h> void putd(int a); ー関数プロトタイプ { putd(123); return 0; } void putd(int a) ー数値を出力するだけで戻り値のない関数 { printf(“%d\n”, a); } ーreturn文による値戻しがない
リスト void型引数の記述例 #include <stdio.h> void opening(void); ー関数プロトタイプ int main(void) { opening(); ー関数呼出側ではvoidを記述する必要はない return 0; } void opening(void) ー引数のない関数を定義 { printf(“program start\n”); }
関数プロトタイプの簡単記述方法 #include <stdio.h> double maxdt(double a, double b); ここに持ってくる int main(void) { ・・・ } double maxdt(double a, double b) { 自作関数の先頭行に’;’を付けて ・・・ }
◎プロトタイプ宣言を省略する方法 #include <stdio.h> double maxdt(double a, double b);ーこのプロトタイプでmaxdt() の仕様が判明しているので int main(void) { double mx; mx = maxdt(11.22, 33.44);-この呼び出しは正しく処理 される ・・・ } double maxdt(double a, double b)-maxdt()関数の本体 { ・・・ }
#include <stdio.h> double maxdt(double a, double b);ー関数定義の先頭行でmaxdt() の仕様が判明するので ・・・ } int main(void) { double mx; mx = maxdt(11.22, 33.44);ーこの呼び出しは正しく処理さ ・・・ れる }
7.3関数にデータを渡す方法 ◎数値を渡す 値による呼び出し(Call by value) リスト 関数呼び出し側a = 11.11, b = 33.33, avdt = ave(a, b);
リスト 関数定義側double ave(double x, double y){ double wk; wk = (x + y) / 2.0; return wk;}
呼び出し側の変数aの値 関数側の変数x呼び出し側の変数bの値 関数側の変数y呼び出し側の変数aの値 関数側の変数x呼び出し側の変数bの値 関数側の変数y 代入 代入
a = 100; avdt = ave(a, 200); 図7-2 値による呼び出し処理 呼び出し側 関数側 avdt=ave(a, 200); double ave(double x, double y) a aの値(100)をxに代入 x 100 100 数値200をyに代入 200 y 200 wk=(x+y) /2.0を計算 wkの値(150)をavdtに代入 avdt 150 wk 150
◎配列を渡す アドレスによる呼び出し リスト 配列を関数に渡す1#include <stdio.h>void disp_ary(int nn[]);int main(void){ int dt[5] = {100, 200, 300, 400, 500}; disp_ary(dt); ー配列の先頭アドレスを渡すreturn 0;}
void disp_ary(int nn[]) ー配列を仮引数にする { printf(“nn[0]=%d\n”, nn[0]);ー配列内容を表示する printf(“nn[4]=%d\n”, nn[4]); }
図7-3 アドレスによる配列私のメカニズム図7-3 アドレスによる配列私のメカニズム main関数側 disp_ary()関数側 disp_ary(dt);でdtの内容(アドレス)である10000をnnに代入する dt 10000 nn 10000 100 dt[0] 10000番地 200 10004番地 dt[1] メモリ内の同じ配列を指す dt[2] 300 10008番地 dt[3] 400 10012番地 dt[4] 500 10016番地
リスト 配列を関数に渡す2#include <stdio.h>void disp_ary1(int nn[], int len);void disp_ary2(int nn[]);int main(void){ int aa[5] = {100, 200, 300, 400, 500}; int bb[6] = {111, 222, 333, 444, 555, -1};-終了マークー1 をにするdisp_ary1(aa, 5);-配列の先頭アドレスと配列長を渡すdisp_ary2(bb);ー配列の先頭アドレスを渡すreturn 0;}
void disp_ary1(int nn[], int len)-lenは配列長情報{ int i; for (i=0; i<len; i++) { printf(“%d ”, nn[i]);ーnn[0]~nn[len-1]を表示} printf(“\n”); ー最後に改行}
void disp_ary2(int nn[]) ー終了マーク方式{ int i = 0; while (nn[i] != -1) { ー-1でない間ループするprintf(“%d ”, nn[i]); ー値を表示++i; } printf(“\n”); ー最後に改行}
◎文字列を渡す ‘A’ ‘B’ ‘C’ ‘D’ ‘E’ 0 これが目印になる
リスト 文字列を関数に渡す#include <stdio.h>void strout(char ss[]);int main(void){ char st[] = “ABCDEF”; strout(st); ー文字配列を渡すstrout”ABab12”); ー直接文字列を渡すreturn 0;}
void strout(char ss[]) ー引数をchar[]にする{ int i; printf(“ss=%s\n”, ss); ー文字列をそのまま出力するi = 0; while (ss[i]) { ーss[i]が’\0’でない間ループするprintf(“%X ”, ss[i]); ーss[i]を16進数出力++i } printf(“\n”); ー最後に改行する}
表7-1 ローカル変数とグローバル変数 ローカル変数 関数内で宣言され、その関数内でのみ参照できる グローバル変数 関数外で宣言され、どの関数からでも参照できる
リスト 文字列を関数に渡す#include <stdio.h>void func(void);int glb; ー関数の外側でグローバル変数gldを宣言int main(void){ int a; ーmain()関数内で使用できるローカル変数aを 宣言a = 10; ー自分のローカル変数に値設定gld = 20; ーグローバル変数に値設定printf(“main a=%d glb=%d\n”, a, glb);ー両方の値を表示func(); ー関数を呼ぶ
return 0;}void func(void){ int b;ーfunc()関数内で使用できるローカル変数bを宣言b = 99;ー自分のローカル変数に値設定printf(“func b=%d gld=%d\n”, b, gld);ー両方の値を表示} gldはmain()関数で設定した値
変数の通用範囲 int glb; int main(void) { } void func(void) { } int a; ・・・ 変数aの通用範囲 変数glbの通用範囲 int b; ・・・ 変数bの通用範囲
◎ローカル変数は衝突しない リスト ローカル変数の機能を見る#include <stdio.h>void func(void);int main(void){ int a; ー変数aを宣言するa = 100; printf(“main a=%d\n”, a);ー変数aの値を表示するfunc(); ー1度関数func()を呼んでprintf(“main a=%d\n”, a);ー再び変数aの値を表示するreturn 0;}
void func(void){ int a; ーこちらでも変数aを宣言するa = 22222; ー独自に値を設定するprintf(“func a=%d\n”, a); ー変数aの値を表示する}
◎ローカル変数が優先される リスト グローバル変数よりローカル変数が優先される例#include <stdio.h>void func(void);int gg = 1234; ー初期設定ありグローバル変数int main(void){ printf(“main gg=%d\n”, gg);ーグローバル変数の値を表示func(); -関数を呼ぶprintf(“main gg=%d\n”, gg);ーグローバル変数をもう1度表示return 0;}
void func(void){ int gg; ー同名のローカル変数を用意するとグローバル 変数ggは操作できなくなるgg = 9999; ー自分の変数ggに値設定printf(“func gg=%d\n”, gg);ー自分の変数ggの値を表示}
◎グローバル変数と外部変数 (1)staticの付かないグローバル変数(外部結合グローバル変数)(2)staticの付いたグローバル変数(内部結合グローバル変数)
auto記憶クラス指定子プログラム実行中にメモリ上に確保されたり消去されたりす る一時的な変数で、関数の中だけで使用できる。extern記憶クラス指定子プログラム実行中に常にメモリ上の同じ場所に存在する恒 久的な変数で、どの関数からも使用できる。externがあると、 よそで設定されたグローバル変数を参照しろという指定にな る。static記憶クラス指定子プログラム実行中に常にメモリ上の同じ場所に存在する恒 久的な変数で、関数の中で使用する方法と、関数の外で使 用する方法がある。auto記憶クラス指定子プログラム実行中にメモリ上に確保されたり消去されたりす る一時的な変数で、関数の中だけで使用できる。extern記憶クラス指定子プログラム実行中に常にメモリ上の同じ場所に存在する恒 久的な変数で、どの関数からも使用できる。externがあると、 よそで設定されたグローバル変数を参照しろという指定にな る。static記憶クラス指定子プログラム実行中に常にメモリ上の同じ場所に存在する恒 久的な変数で、関数の中で使用する方法と、関数の外で使 用する方法がある。
変数の通用範囲 #include <stdio.h> void func(void); int gg = 1234; int main(void) { printf(“main gg=%d\n”, gg); func(); return 0; } グローバル変数を記述 グローバル変数ggを使用 myprg2.cにある関数を呼ぶ
myprg2.cの内容 #include <stdio.h> extern int gg; void func(void) { printf(“func gg=%d\n”, gg); } よそで宣言されている グローバル変数ggを利用可能にする、という宣言 myprg1.cのグローバル変数ggを使用できるようになる
◎static記憶クラス指定子 リスト static変数の使用例#include <stdio.h>void max_auto(int n);void max_static(int n);int main(void){ max_auto( 40); max_auto(100); max_auto( 80); max_static( 40); max_static(100); max_static( 80); 3つの値でmax_auto()を呼ぶ 3つの値でmax_static()を呼ぶ
return 0;}void max_auto(int n){ int max = 0; ー変数maxは自動変数if (n > max) max = n; ー最大値を記憶printf(“max_auto max=%d\n”, max); ーその値を出力}void max_static(int n){ static int max = 0; ー変数maxは静的変数if (n > max) max = n; ー最大値を記憶printf(“max_static max=%d\n”, max);ーその値を出力}
記憶クラスの使い分け法(1)通常は →自動変数を使う。ただし”auto”は省略する(2)値を保持したいときは →静的変数を使う(staticを付ける)(3)共通に使用したいときは→グローバル変数を使う
リスト 外部変数を使ったデータやりとりの例#include <stdio.h>void wasa(void);int n1, n2, wa, sa; ーグローバル変数の宣言int main(void){ n1 = 300; n2 = 100; wasa(); ー引数なしで関数コールするprintf(“n1=%d n2=%d 和=%d 差=%d\n”, n1, n2, wa, sa); return 0;}
void wasa(void) ーグローバル変数を使うので引数不要{ wa = n1 + n2; ー戻り値もグローバル変数に入れるwa = n1 - n2;}