プログラミング実習 I 05 関数 (1) 人間システム工学科井村誠孝 m.imura@kwansei.ac.jp
関数とは p.162 数学的には入力に対して出力が決まるもの C 言語では入出力が定まったひとまとまりの処理 入力や出力はあるときもないときもある main() も関数の一種 何かの仕事をこなしてくれる魔法のブラックボックス 例 : printf() 関数中で行われている処理の詳細を使う側は知らないが, とにかく, 画面に表示してほしい文字列 ( と変数 ) を教えると, 適切に表示処理を行ってくれる
数学の関数と C 言語の関数 p.162 入力 入力された値を 2 乗する関数 出力 f(x) 5 25 入力 "x の値は %d" x (x=10 とする ) 文字列や変数を書式に従って表示する関数 printf() 出力 画面に x の値は 10 と表示
関数はどういうときに便利か ある処理を複数回行う場合 同じソースコードを複数回書くのは面倒, かつ, 変更するときが大変. 間違える可能性も高くなる. ある処理が複数の処理から成り立っている場合 長い手順からなる処理を, 段階ごとに分割し関数として実装すると, 見通しがよくなる. 処理の入力と出力が明確になり, その処理のみに必要な変数などを関数内に隠蔽することができる.
関数の使い方は皆さん既に知っている p.162 printf() や scanf() は関数 C 言語が標準的に用意してくれている標準関数 ( 標準ライブラリ関数 ) の一つ 実はmain() も関数 関数の使い方は既に知っている ソースコード中に関数名と引数 ( ひきすう ) を書く printf("xの値は %d n", x); 加えて, どのような関数を使うのか ( 関数の仕様 ) を,Cコンパイラに教えることも必要 #include <stdio.h>
関数を自作する方法を学ぶ p.163, 164 p.163 プログラムの形式 5.1 関数の定義 p.164 リスト 5.2 整数の正のべき乗を計算する関数 関数の型名 関数名 引数 1 の型名 引数名 1 引数 2 の型名 引数名 2 int powint(int x, int p) { int y = 1; 変数定義 ( 複数行でももちろん可 ) 文 1; } while (p-- > 0) { y *= x; } return y; 文 2; : 関数値 ( 返値あるいは戻り値とも言う )
関数の呼び出しに関連する用語 p.164 p.164 リスト 5.3 を確認 2 0 int powint(int x, int p) { int y = 1; while (p-- > 0) { y *= x; } return y; } : j = powint(2, i); return 文 仮引数 実引数 x p 0 2 i
プロトタイプ宣言 p.166 コンパイラはソースコードを上から下へと一度だけ解釈する リスト 5.3 の関数 powint() は,main() 内で使用される前に, 関数の定義が書かれていた. main() で使用される時には, コンパイラは既に powint() の引数の個数, それぞれの引数の型, 関数値 ( 返値 ) の型などの情報を知っていた. 適切にコンパイル可能 では, 関数の定義が, 関数が呼び出される場所の後ろや, 別のソースコードで書かれている場合には, どうすればよいのか? プロトタイプ宣言をしておく.
プロトタイプ宣言の方法 p.168 p.168 リスト 5.4 を確認 関数の型名 関数名 引数 1 の型名 引数名 1 引数 2 の型名 引数名 2 int powint(int x, int y); セミコロン 関数の定義の1 行目とほぼ同じだが, 末尾にセミコロンを付ける. 仮引数の変数名は, 関数の定義のものと違っていてもよい ( が, 積極的に変える必要もない ).
標準関数のプロトタイプ宣言はどこに? p.167 標準関数 ( 標準ライブラリ関数 ) printf() などに関 する情報をコンパイラはどうやって知ったのか?= 標準関数のプロトタイプ宣言はどこにあるか? これまで定型的に記述していた, ソースコード冒頭の #include <stdio.h> に秘密がある. ヘッダファイルと呼ばれる. ちなみに関数の本体はライブラリファイルに入っている.
#include <stdio.h> は何か? p.167 プリプロセッサ コンパイルの前処理機能 行頭の # から始まる命令がプリプロセッサ向けの命令 他のファイルの読み込み : #include 文字の置換 : #define コンパイル本処理との違い =C 言語の文法の解釈は行わない インクルード プリプロセッサによる他のファイルの読み込み #include <stdio.h> は,( システムのどこかにある )stdio.hという名前のファイル ( ヘッダファイル ) の内容を読み込み, ソースコードのこの場所に展開する.
関数の呼び出し手順 p.175 p.175 中段 関数の呼び出し手順 関数の呼び出しが行われる 実引数の値を, 仮引数にコピー ( 値渡し ) その関数の定義部分を実行する 計算結果をその関数の値として返す 関数を呼び出したプログラムに制御が戻る
仮引数と実引数の確認 p.174 リスト 5.10 抜粋 int main(void) { int t, m; : combi(t, m); : } 実引数 int combi(int n, int r) { : } 箱をまるごと渡すのではない!! 仮引数 変数 t と m は関数 main() 専用 3 t 3 n 変数 n と r は関数 combi() 専用 2 m 値渡し 2 r
局所変数 : 変数の通用範囲 p.176 変数には通用範囲がある. 原則 : 定義されたブロック {} の中でのみ有効. ソースコードの以降全部で有効, ではないので注意. 一番外側 (main() 関数などの外 ) で定義された場合は定義位置以降全体で有効 ( グローバル変数 ). 関数の中で局所変数の値を書き換えても, 呼び出し側の変数は影響を受けない. 関数から複数の値を返したい場合は, ポインタを用いる ( 本実習では扱わない ) けど配列を関数に渡すところで, その香りが出てくるんや
関数の引数は 値渡し int func(int x) { x = x * 2; return x; } int main(void) { int x = 1; int y; } y = func(x); printf("x = %d n", x); 呼出元と呼出先の変数は, 名前は同じでも別のもの なので, 関数内で x を 2 倍しても... p.176 ここで出力される x の値は, 2 ではなく 1.
その他の知識 p.180 引数や返値が無い場合 : void 型 void ex2(int x); void ex3(void); 値を返さない関数 引数が無く値を返さない関数 呼出時の引数の個数は, プロトタイプ宣言 ( もしくは関数定義 ) の引数の個数と一致する必要あり. 変数の型が異っている場合, 自動的に ( 暗黙のうちに ) 型変換が行われる. 同じ名前の関数は定義できない. 注 : C++ ではできるようになっており, どの関数を呼び出すかは引数の型で区別される.