復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される. 関数を呼び出す側の実引数の値が関数内の仮引数(変数)に コピーされる 関数内で求めた値はreturn文によって関数値として呼び出し側に戻される. #include <stdio.h> float menseki(float a, float b) { return (a * b / 2); } int main(void) float x, y, kekka; printf("底辺は?"); scanf(" %f ", &x); printf("高さは?"); scanf(" %f ", &y); kekka = menseki(x, y); printf("面積は%fです.\n", kekka); x,y:実引数 a, b: 仮引数 仮引数もローカル変数 →関数内でのみ有効 関数の定義 関数の呼び出し
復習 前回の関数のまとめ(2) 関数はプログラム上の部品(機能単位)である. 関数内の変数はお互いに独立である(干渉しない). #include <stdio.h> float menseki(float a, float b) { float s; s = a * b / 2; return s; } int main(void) float a, b, kekka; printf("底辺は?"); scanf(" %f ", &a); printf("高さは?"); scanf(" %f ", &b); kekka = menseki(); printf("面積は%fです.\n", kekka); menseki()関数 同じ変数名a,bでも,関数が違うと,別の変数と見なされる main()関数
復習 関数定義におけるreturn 文 float menseki(float a, float b) { float s; s = a * b / 2; return s; } float menseki(float a, float b) { return a * b / 2; } return文の文法 return 式; return文を実行すると関数を終了する.式の値を関数値として戻す. int func(int x, int y) { if (x*y % 2 == 0) return 1; } return文を実行しない場合があるのでダメ. int func(int x, int y) { if (x*y % 2 == 0) return 1; } else return 0; return文は複数あってもOK.但し,どのような場合でも必ずその一つを実行すること. return文で戻る値を返り値 あるいは戻り値と呼ぶ
menseki()関数の戻り値が変数に代入されていない! float menseki(float a, float b) { float s; s = a * b / 2; return s; } int main(void) float x, y; printf("底辺は?"); scanf("%f", &x); printf("高さは?"); scanf("%f", &y); menseki(x, y); printf("計算はしたよ\n"); printf(・・・) scanf(・・・) main() これらは全て関数 但し,一般に戻り値は利用されない menseki()関数の戻り値が変数に代入されていない! 質問 これはコンパイル エラーになるか? 答え エラーにはならない. 関数値の戻り値は代入され なくてもかまわない.
引数としてvoidと書くと,引数が無いことを宣言 関数値を持たない(返さない)関数の定義 void kansu(float a, float b) { .... return; } voidは戻り値が無いことを宣言 何も返さないので,return 式 ; とは書かない. return文の省略も可能! 引数としてvoidと書くと,引数が無いことを宣言 int main(void) { int x; x = kansu(3, 4); printf("x=%d, %d", x, kansu(2,5)); } int func(void) { return 5; } int main(void) printf("値は%d", func()); void 宣言された関数の関数値を利用しようとするとエラー
main()関数 main()関数は特殊な関数である 関数値は int型 (関数値を戻す) voidなので引数は無い int func(void) { return 5; } int main(void) printf("値は%d", func()); voidなので引数は無い void 宣言されていない関数ではreturn文は省略できないはず!! main()関数は特殊な関数である
?? 関数の戻り値のまとめ 引数を10倍する関数 疑問 なぜこのmul10()関数は 意図どおりに働かないか? 戻り値がある関数でも,必要がなければ,呼び出し側でそれを使わなくても(代入しなくても)かまわない. 戻り値が無い関数を定義する場合,あらかじめvoid宣言をする.この場合,return文で値を戻さない.また,return文自体も省略可. void宣言された関数で戻り値を利用しようとするとエラーになる. void mul10(int a) { a = a * 10; return; } int main(void) int x = 12; mul10(x); printf("x = %d", x); 引数を10倍する関数 疑問 なぜこのmul10()関数は 意図どおりに働かないか? x = 12 ??
x a 12 120 12 引数の値渡し 引数を10倍する関数 関数呼び出し main()関数 mul10()関数 変数 引数の値のコピー int main(void) { int x = 12; mul10(x); printf("x = %d", x); } void mul10(int a) { a = a * 10; return; } 原則 引数のコピーが関数に渡され,呼び出し側の変数は変化しない. ⇒値渡し(call by value) x = 12 関数呼び出し a 12 x main()関数 変数 mul10()関数 12 引数の値のコピー 120 局所変数 ローカル変数 return文実行 例外 ポインタ引数,配列引数 ⇒参照渡し(call by reference)
配列を引数とする関数 n個のデータの合計を求める関数 データの個数がn個 (≠配列宣言の要素数) データを入れる配列 #include <stdio.h> int sum(int data[], int n) { int s = 0, i; for (i = 0; i < n; i++) { s = s + data[i]; } return s; } int main(void) int i, aa[50], s; // 配列aa[]に30個のデータを入力する ・・・ //省略 s = sum(aa,30); printf(“データの合計は%d\n”,s); データの個数がn個 (≠配列宣言の要素数) 理由:配列宣言時の要素数と有効なデータ数は 同じではないので! データを入れる配列 要素数を空欄にする.→data[n]× data[0]× aa[0]からaa[29]に30個の値を代入しておく 関数呼び出し 配列名のみ書く.[ ]は不要 有効なデータの個数は30個 配列引数は自動的に参照渡しだが,この例では配列要素の値は変化させていない
配列引数(参照渡し)を用いた関数 n個のデータの値を10倍する関数 関数宣言と引数の書き方は同じ #include <stdio.h> void mul10(int data[], int n) { int i; for (i = 0; i < n; i++) { data[i] = data[i]*10; } } int main(void) int i, aa[50], s; // 配列aa[]に30個のデータを入力する ・・・ //省略 mul10(aa,30); printf(“データを全て10倍すると”); ・・・ //データの表示(省略) 関数宣言と引数の書き方は同じ 配列引数は参照渡しであるため,呼び出し側の配列の値が変化する! 関数の呼び出し方法も同じ 配列aa[0]~aa[29]の値は全て10倍されている. 参照渡しにより配列要素の値を変化させる例
引数のまとめ 値渡し(基本) 関数を呼び出した側の実引数の値が変化しない. 配列引数とポインタ引数を除く他の全ての引数 参照渡し(例外) 関数を呼び出した側の実引数の値が変化する. 以下の二つのみ. 配列引数 ポインタ引数(2年で学習)
関数のデバッグ [A] ツールバーでデバッグを始める手順 ツールボタンで右クリックして,デバッグを選ぶ デバッグツールバーからボタンを選ぶ ステップインは関数内部に入って1行づつ実行する (3) (2) (1) (1)ステップオーバー 次の行を実行 (2) ステップイン 次の行を実行 (3) デバッグの中止 デバッグをやめる [B] メニューでデバッグを始める手順 デバッグメニューで,ステップオーバーを選ぶ