プログラミング演習 初級編 2004年7月15日(木) 奈良先端科学技術大学院大学 情報科学研究科 猿渡 洋 斎藤 将人 新保 仁 本日の内容 I. II. III. 関数の基礎:宣言と呼び出し 変数の有効範囲と引き渡し 再帰呼び出し I. 関数宣言と関数の 呼び出し 関数とは y = f(x) 関数は、名前を持つ(関数名:f) 関数へ引き渡す変数(引数:x) 複数あることも f(x1, x2), f(x1, x2, x3), … 全くないこともある: f() 関数からの戻り値 (ないこともある) 計算や処理を、機能ごとにまとめたもの 関数の基本形 関数の宣言 関数名 引数(関数に与える値)の個数と型 戻り値の型 戻り値を持たない関数の場合は void 型 内部処理の記述 これまでの main() と同様でよいが, void 型以外の関数は,必ず “return 値;” で、戻り 値を指定して関数を終了する。 関数の「宣言」 #include <stdio.h> 戻り値の型(戻り値が無い関数の場合 void) int square(int x) { return x * x; } 仮引数:実行時に与えられる引数を 仮に x として処理を書く ここの値が戻り値となる (次ページへ続く) 関数の呼び出し (前ページからの続き) int main() 実は main() も int 型の関数. { int a, b; printf("Type any integer.\n"); scanf("%d", &a); a:実引数 b = square(a); この値を引数とし関数を呼び出し printf("%d\n", b); return 0; } main()関数の戻り値 処理の流れ main() a に値を代入 b = square(a); square() 実引数 a として 呼び出し square(a)を計算 bに代入 x * x を計算 戻り値 出力 仮引数 x で受ける 関数を使うメリット 同じ処理を何度も書く必要がなくなる 同じ処理を他のプログラムでも再利用しやすい プログラムを見やすくできる プログラミングの心得 プログラムは、可能なかぎり 独立な最小単位に分離して 個々に関数化するよう こころがけよう! 関数例:階乗計算 int factorial(int n) { その関数の中だけで使用する変数は,そ の関数の中で宣言する (ローカル変数). int i, x; x = 1; for (i=2; i<=n; i++) { x = x * i; } return x; } 関数の型宣言 関数は呼び出しより前に宣言する. factorial() 関数の宣言が main() より後にあると コンパイルエラーとなる. 関数の呼び出し型 (戻り値および引数の型,数) だけをあら かじめ宣言しておき、実際の関数はあとで書く. int factorial(int n); をファイルの先頭に書いておくとそれ以降, 使えるようになる. 演習課題 演習5-1 n 個の要素から r 個の組を取り出す際の組み合わせ の数 nCr を計算する関数 combination を作成し, その動作を確認せよ. (ヒント:複数の引数はコンマで区切って宣言・呼び出 しする) int combination(int n, int r); II. 変数の引き渡しと 有効範囲 関数間のデータの授受 1. 2. 3. 値渡し ポインタによるアドレス渡し 外部変数渡し 1. 値渡しの例: square 関数 int square(int x) { return x * x; } int main() { int a, b; … b = square(a); … } 1.値渡し 実引数の値を関数側の仮引数にコピー 呼ばれた関数内で仮引数の値を変えても元の実引数に影 響しない Cの標準的な引数の渡し方 square() main() int a; b = square(a); a の値を 引き渡す 仮引数 x で 受ける 値渡しの例 #include <stdio.h> void display(int n) { n = 2; printf(“In 'display' function, n=%d\n”, n); } int main() { こちらの n の値は int n = 1; 変化する? display(n); printf(“In 'main' function, n=%d\n”, n); return 0; } 2.アドレス渡し 実引数の値ではなくそのポインタを渡す 関数内ではポインタを使って実引数のアドレスを直接参照 main() int a; 実引数 a の アドレスを 引き渡す b=square(&a); 元の実引数 a を ポインタで 直接参照できる square() *x で a の値を 直接参照 アドレス渡しの例 #include <stdio.h> void init(int x[], int *y) { int i: for(i=0;i<100;i++) x[i] = i; *y = i; } 配列 x[] とポインタ y が指し 示すアドレスに値を書き込む int main() { int a[100], n = 0; init(a, &n); printf("n=%d\n", n); while (n-- > 0) printf("%d:%d\n", n, a[n]); } アドレス渡しの使い方 関数から2つ以上の値を返したいとき 呼ばれた関数内で元関数の値を変えたいとき 例: scanf("%d", &i) scanf内で i の値を変更 配列を引き渡すとき 3.外部変数渡し 引数を用いない変数の引渡し法 関数の外で外部 (グローバル) 変数を定義して、そこを介し て値をやりとりする。 外部引渡しの例 #include <stdio.h> int a[100]; 配列 a[] をグローバル変数として定義 int init() { int i: for(i=0; i<100; i++) a[i] = i; return i; } int main() { 外部変数a[]を直接参照 int n; n = init(); printf(“n=%d\n”, n); while (n-- > 0) printf(“%d:%d\n”, n, a[n]); return 0; } 変数の有効範囲(スコープ) 内部変数(ローカル変数) ある関数内で宣言された変数 その関数内でのみ参照可能 関数が終わると消滅 他の関数からは見えない。独立。 外部変数(グローバル変数) 関数の外で宣言された変数 以降の全関数から参照できる。 関数終了以後も値が残る。 演習問題 演習5-2 演習4-1 の商品一覧表示プログラムを関数を使って書き直せ. 商 品リスト (商品名, 単価からなる構造体の配列) は固定ではなく, 呼び出し側で指定できるようにすること. ヒント: 構造体配列(商品リスト)へのポインタと,配列の要素数 (商品数)を引数とするとよい. 以下の二つの商品リスト a, b それぞれに対して, 関数の動作を確 認せよ. 商品リスト a (商品数 3) 商品リスト b (商品数 2) ID 商品名 単価(円) ID 商品名 単価(円) 0 Pencil 60 0 Toothbrush 200 1 Eraser 50 1 Toothpaste 350 2 Ruler 120 III. 再帰呼び出し 階乗計算:再帰呼び出しを使って int factorial2(int n) { 自分自身を呼び出し int r; if (n > 1) { r = n * factorial2(n - 1); } else { r = 1; } return r; n が 1 以下ならそれ以上は呼び出さない } 変数の有効範囲(スコープ) 内部変数(ローカル変数) ある関数内で宣言された変数 その関数内でのみ参照可能 関数の実行が終わると消滅 他の関数(再帰的に呼ばれた同じ関数も含む)からは見 えない。独立。
© Copyright 2024 ExpyDoc