200 likes | 358 Vues
第 7 週 関数(1). プログラミング言語 2014 立命館大学情報理工学部. 関数の種類 P.114. main 関数 C 言語のプログラムでただ1つ存在. 必ず main 関数から実行される. ライブラリ関数 あらかじめ提供されている関数 ソースコード内でヘッダファイルを #include し, コンパイル時にライブラリをリンクして使う(後述) 自分で作る関数 ソースコード内 で main 関数とは別の関数を定義 次から のスライドで記述方法を説明 main 関数の前に置く場合,後に置く場合で書き方に違い
E N D
第7週関数(1) プログラミング言語 2014 立命館大学情報理工学部
関数の種類 P.114 • main関数 • C言語のプログラムでただ1つ存在. • 必ず main関数から実行される. • ライブラリ関数 • あらかじめ提供されている関数 • ソースコード内でヘッダファイルを#includeし,コンパイル時にライブラリをリンクして使う(後述) • 自分で作る関数 • ソースコード内でmain関数とは別の関数を定義 • 次からのスライドで記述方法を説明 • main関数の前に置く場合,後に置く場合で書き方に違い • 最初は,前に置く場合を説明
List6-1 P.115 関数の定義と呼出し (必須知識) 実行してみよう Fig.6-4 (P.116) も参考に /* 2つの整数の大きい方の値を返す関数 */ #include <stdio.h> intmaxof(int x, int y) { if( x > y ) return x; else return y; } int main(void) { intna, nb; puts(“2つの整数を入力 “); printf(“整数1 : “); scanf(“%d”, &na); printf(“整数2 : “); scanf(“%d”, &nb); printf(“大きい方の値は%dです.\n”, maxof(na, nb)); return 0; } main関数から開始 xに83,yに45を代入 maxof(83,45)を 関数呼び出し 2つの整数を入力 整数1 : 83 整数2 : 45 大きい方の値は83です. naの値は83 nbの値は45 main関数に戻った時の maxof(83,45)の値はreturn された値, つまり,83
関数定義 P.114, p.116, p.117(必須知識)呼び出される側の書き方 関数頭部: 型 関数名(型 仮引数1, 型 仮引数2, …) この関数が返す返却値の型 仮引数の型 intmaxof( int x, int y) { if(x > y) return x; else return y; } return 式; で示された式の 評価値が この関数が返す 返却値(戻り値) 関数本体 ={} で囲まれた複合文
関数呼び出し P.115(必須知識)呼び出す側の書き方 • 関数呼び出し式: 関数名(実引数1,実引数2, …) • 関数呼び出し式を評価すると,returnで返却される値 • 返却値の型は,前スライドにあった「関数が返す返却値の型」 int main(void) { intna, nb; naに83, nbに45を入力する printf(“大きい方の値は%dです.\n”, maxof(na, nb)); return 0; }
List6-3 P.119 関数は複数あってもよい 左からの続き int main(void) { int p, q, p2, q2; puts("2つの整数を入力してください\n"); printf("整数p : "); scanf("%d", &p); printf("整数q : "); scanf("%d", &q); p2 = sqr(p); q2 = sqr(q); printf(“pの2乗とqの2乗の差は%d\n",diff(p2, q2)); return 0; } /* 2整数の2乗の差 */ #include <stdio.h> intsqr(int x) { return x * x; } int diff(int x, int y) { return x>y ? x-y: y-x; } 右へ続く printf(“pの2乗とqの2乗の差は%d\n", diff( sqr(p), sqr(q) ); と書いてもよい.
List6-4P.120ループを持つ関数関数本体はmain関数と同じような構造List6-4P.120ループを持つ関数関数本体はmain関数と同じような構造 局所変数: 関数内で定義される変数(後述) 左からの続き /* べき乗 */ #include <stdio.h> double power(double dx, int no) { inti; double tmp = 1.0; for( i = 1; i <= no; i++) tmp*= dx; return tmp; } intmain(void) { intn; double x; printf(“実数は?:"); scanf("%lf",&x); printf(“整数は?:"); scanf("%d",&n); printf("%.2fの%d乗は%.2fです.\n", x, n, power(x, n)); return 0; } 右へ続く [注] scanf(“%lf”,&x): 変数 xが,float型ならf,double 型なら lf
値渡し P.120必須知識 List 6-4 の power() が main()から呼ばれるとき • 呼出されると,関数内の変数用のメモリ出現 • 呼出し側の値が,呼ばれる側の変数に複製 • 呼ばれる側の変数を変更しても,呼出し側の変数に影響なし • 返却値を返す • 関数の局所変数はreturn後, 呼ばれる側 power() 関数内の局所変数 tmp 関数内の局所変数 i 関数の仮引数 n 消滅 関数の仮引数 x 関数の返却値(関数値) 呼び出し側 main() ( ,) = power 呼出し側の変数 実引数 n 実引数 x
List6-5 P.121 仮引数の変更値渡しを活かしてコンパクト化 /* 局所変数をループ変数に利用*/ double power(double dx, int no) { double tmp = 1.0; while( no-- > 0) tmp*= dx; return tmp; } double power(double dx, int no) { inti; double tmp = 1.0; for( i = 1; i <= no; i++) tmp*= dx; return tmp; } power() を変更 呼ばれる側の変数を変更しても,呼出し側の変数に影響なし この例では,仮引数をループ変数に使って,コンパクト化
List6-6 P.121 関数を呼び出す関数 intmaxof(int x, int y) { if( x > y ) return x; else return y; } int max4(int w, int x, int y, int z) { return maxof(maxof(w,x), maxof(y,z)); } int main(void) { : max4(a, b, c, d); : } ここでmax4()の値が求められる
関数呼び出しとメモリ y y y maxof maxof maxof x x x 返却値 返却値 返却値 maxof( maxof( w, x ), maxof( y, z ) ) z y x w max4() max4の返却値 関数実行終了後,そのためのメモリは消滅 max4( , , , ) c d a b main()
List6-7 P.122値を返さない関数 関数の型が void 実行してみよう /* 直角三角形 */ #include <stdio.h> void put_starts(int no) { while( no-- > 0) putchar('*'); } int main(void) { inti, ln; printf("何段ですか: "); scanf("%d", &ln); for(i = 1; i <= ln; i++) { put_stars(i); putchar('\n'); } return 0; } % ./triangle 何段ですか: 6 * ** *** **** ***** ****** % i行目に i個の* i個の印字をひと塊の機能とみなす
今回押さえるべきプログラム List 6-8 P.123汎用性P.129 印字する文字を引数に /* 左に空白がある直角三角形 */ #include <stdio.h> void put_nchar(intch, int no) { while( no-- > 0) putchar(ch); } int main(void) { inti, ln; printf("何段ですか: "); scanf("%d", &ln); for(i = 1; i <= ln; i++) { put_nchar(' ', ln -i); put_nchar('*', i); putchar('\n'); } return 0; } 何段ですか:6 i個の* ln-i個の空白 * ** *** **** ***** ****** これを1からlnまでループ この関数は2つの機能に使え,汎用性が高い
List6-9 P.124 仮引数を受け取らない関数 仮引数が void 実引数は空 intrev_int(intnum) { inttmp = 0; if(num > 0) { do { tmp = tmp*10+num%10; num /= 10; } while(num > 0); } return tmp; } int main(void) { intnx = scan_unit(); printf("反転した値は%d\n", rev_int(nx)); return 0; } #include <stdio.h> intscan_unit(void) { inttmp; do { printf("非負の整数: "); scanf("%d", &tmp); if(tmp < 0) puts(“\a間違い"); } while( tmp < 0 ); return tmp; } 右へ続く 関数の返却値で 初期化 \a は「警告音を鳴らせ」
ブロック有効範囲(block scope)P.125必須知識 { }内で定義された変数は{ }の内側で有効 • ブロック(block): { と } で囲まれた部分 • 変数の有効範囲をスコープという • ブロックで定義された変数のスコープは,ブロック内 intscan_unit(void) { inttmp; printf("非負の整数: "); scanf("%d", &tmp); return tmp; } intrev_int(intnum) { inttmp = 0; do { tmp = tmp*10+num%10; num /= 10; } while(num > 0); return tmp; } このtmp これらは このtmp scan_unit() rev_int() これらは main() tmp tmp 関数内の局所変数を格納したメモリは 関数実行終了後,消滅するので, 当たり前といえば当たり前 返却値 返却値
ファイル有効範囲(file scope) P.126 • どのブロックにも定義が含まれない変数のスコープは,その定義からファイルの最後まで • ファイル・スコープを持つ変数は,使いにくいので,薦められない. 宣言と定義 P.127 • 定義:変数や関数がメモリ上に割付けられる • 宣言:変数や関数の型など使い方(仕様)を示す
プロトタイプ 関数の原型宣言(P.127)(必須知識) #include <stdio.h> void put_starts(intnumber); int main(void) { inti, ln; printf("何段ですか: "); scanf("%d", &ln); for(i = 1; i <= ln; i++) { put_stars(i); putchar('\n'); } return 0; } void put_starts(int no) { while( no-- > 0) putchar('*'); } List6-7 を修正 • main()のあとで,関数を定義する場合 • main()が,関数の • 返却値の型 • 引数の数 • 引数の型 を知る手段が必要 プロトタイプ宣言を前に(最後に ; を忘れずに)
ヘッダファイルと #includeP.128 (必須知識) • プロトタイプ宣言は,関数の仕様を示す. • これが最初にあると,いろいろな関数を使える. • printf(), scanf()などを使うためのプロトタイプ宣言はヘッダファイルstdio.hに入っている. • #include • その1行が,ファイルの内容と入れ替わる [例]#include <stdio.h> C言語であらかじめ用意されている,関数をそのファイルで使用できるようになる
クイズ:プログラムを実行した結果を求めよ #include <stdio.h> #define MAX_NUMBER (4) int M(int left, int right) { return left > right ? left : right; } int m(int left, int right) { return left > right ? right : left; } int main(void) { int d[MAX_NUMBER] = {1, 9, 3, 8}; printf("答えは%d\n", m( M(d[0], d[1]), M(d[2], d[3]))); return 0; }
正解 • M()は2つの整数のうち,大きいほうを返す • m()は2つの整数のうち,小さい方を返す. • 最初にM(1,9)の値は9 • ついでM(3,8)の値は8 • 最後にm(9,8)の値は8 • よって,正解は8