1 / 30

第 5 章 関数の作成

ここから後編. 第 5 章 関数の作成. 今まで使ってばっかりだった関数 この章ではその作り方を教えていきます. 値を返さない関数 (1). 値を返さない関数とは、式や引数に含めることができない関数 たとえば、. s rand 関数 → 値を返さない関数 t ime 関数 →値を返す関数. srand (time(NULL)) + 1. とは書きませんよね. ここでは. です. 値を返さない関数 (2). #include < stdio.h > int main( void ){ double height,weight,bmi ;

edmund
Download Presentation

第 5 章 関数の作成

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. ここから後編 第5章 関数の作成 今まで使ってばっかりだった関数 この章ではその作り方を教えていきます 第5章 関数の作成

  2. 値を返さない関数(1) 値を返さない関数とは、式や引数に含めることができない関数 たとえば、 • srand関数→値を返さない関数 • time関数→値を返す関数 srand(time(NULL))+ 1 とは書きませんよね ここでは です 第5章 関数の作成

  3. 値を返さない関数(2) #include <stdio.h> int main(void){ doubleheight,weight,bmi; printf("身長(m) "); scanf("%lf",&height); if(height <= 0){ printf("エラー\n"); return 0; } printf("体重(kg) "); scanf("%lf",&weight); if(weight <= 0){ printf("エラー\n"); return 0; } bmi=weight/height/height; printf("BMI %lf\n",bmi); return 0; } エラーが起きた時の メッセージを変えたい!! 数か所変えなければならない マクロ使う? エラーが起きた時に 音が出るように変えたい!! 数か所変えなければならない マクロでは対応不可 こうなった時のために エラーを表示する関数を 作ろう 第5章 関数の作成

  4. 値を返さない関数(3) 値を返さない、引数がない関数の定義 • main関数など関数の外に書く • 使いたい場所より上に書く 文法 void 関数名(void){ 関数が呼び出時に実行する文1; 文2;・・・ } 注意事項 関数を作るといっても今までの関数や文法などの 組み合わせで新たな関数を作るだけです。 未知の関数を作るわけではなく 決して難しくないので安心してください 第5章 関数の作成

  5. 値を返さない関数(3) #include <stdio.h> voidshowErrorMessage(void){ printf("エラー\n"); } int main(void){ doubleheight,weight,bmi; printf("身長(m) "); scanf("%lf",&height); if(height <= 0){ showErrorMessage(); return 0; } printf("体重(kg) "); scanf("%lf",&weight); if(weight <= 0){ showErrorMessage(); return 0; } bmi=weight/height/height; printf("BMI %lf\n",bmi); return 0; } エラーメッセージを 表示するだけの showErrorMessage関数が できました 第5章 関数の作成

  6. 引数(1) ただ「エラー」と表示させるだけではなく 何がエラーなのかも表示したいですよね ここで活躍するのが、そう、引数です 改行は普通しない 値を返さない、引数のある関数の定義 文法 void 関数名(引数1のデータ型 引数1の名前, 引数2のデータ型 引数2の名前, ・・・・){ 関数が呼び出時に実行する文1; 文2;・・・ } 第5章 関数の作成

  7. 引数(2) たとえば、名前bのint型を引数に持つ関数Aがあるとします • A関数内ではbは変数のように扱える • 代入、参照が可能 • bの初期値はmain関数で指定した100 void A(int b){    ・・・ } int main(void){ A(100); return 0; } 文法 void 関数名(引数1のデータ型 引数1の名前, 引数2のデータ型 引数2の名前, ・・・・){ 関数が呼び出時に実行する文1; 文2;・・・ } 第5章 関数の作成

  8. 引数(3) #include <stdio.h> //causeが0なら身長,1なら体重が不正 voidshowErrorMessage(int cause){ if(cause == 0){ printf("身長が不正\n"); }else if(cause == 1){ printf("体重が不正\n"); } printf(“エラー\n"); } int main(void){ doubleheight,weight,bmi; printf("身長(m) "); scanf("%lf",&height); if(height <= 0){ showErrorMessage(0); return 0; } printf("体重(kg) "); scanf("%lf",&weight); if(weight <= 0){ showErrorMessage(1); return 0; } bmi=weight/height/height; printf("BMI %lf\n",bmi); return 0; } 本来であればcauseの取りうる値を マクロにすべきですが、スペースがないので お許しください・・・ 第5章 関数の作成

  9. 引数(4) 引数はコピーされた値に過ぎない → 呼び出し先関数内で引数を変更しても 呼び出し元の変数は一切影響を受けない #include <stdio.h> void a(int b){ b=1; } int main(void){ int c=0; a(c); printf("%d\n",c); return 0; } main関数 a関数 0 int c = 0; Cには 影響しない c 0 0 a(c); b c 1 0 b = 1; b c 第5章 関数の作成

  10. return文(1) showErrorMessage関数ですが、 引数が0,1以外の時は関数を強制終了させたいですね 値を返さない関数では return文を使って関数を強制終了できます 文法 return; では先ほどのプログラムを改造しましょう 第5章 関数の作成

  11. return文(2) #include <stdio.h> voidshowErrorMessage(int cause){ if(cause == 0){ printf("身長が不正\n"); }else if(cause == 1){ printf("体重が不正\n"); }else{ return; } printf(“エラー\n"); } int main(void){ doubleheight,weight,bmi; printf("身長(m) "); scanf("%lf",&height); if(height <= 0){ showErrorMessage(0); return 0; } printf("体重(kg) "); scanf("%lf",&weight); if(weight <= 0){ showErrorMessage(1); return 0; } bmi=weight/height/height; printf("BMI %lf\n",bmi); return 0; } 実行されない文を書くのは無駄だと思うかも知れませんが、 ひょっとしたら引数の指定を間違えるかもしれません 第5章 関数の作成

  12. 値を返す関数(1) #include <stdio.h> intmain(void){ intn, m, nPm, mPm, i, j; printf("n "); scanf("%d",&n); printf("m "); scanf("%d",&m); nPm=1; mPm=1; for(i = n;i > n - m;i--){ nPm *= i; } for(j = m;j > 0;j--){ mPm *= j; } printf("nCm=%d\n",nPm/mPm); return 0; } 左は を求めるプログラム より、 を求める関数を作れば すっきり書けるのではないか 同じような処理を複数回書くのは プログラミングでは嫌われる 第5章 関数の作成

  13. 値を返す関数(2) 改行は普通しない 値を返さない、引数のある関数の定義 文法戻り値データ型関数名(引数1のデータ型 引数1の名前, 引数2のデータ型 引数2の名前, ・・・・){ 関数が呼び出時に実行する文1; 文2;・・・ } 引数がない場合は void また、値を返す文も必要ですね。 return文が、値を返し、関数を強制終了します 文法 return戻り値; 値を返さない関数の時とは違い、 値を返すという役割があるので注意しよう! 第5章 関数の作成

  14. 値を返す関数(3) #include <stdio.h> int permutation(intn,int m){ inti , result; i = n; result = 1; for(i = n;i > n - m;i--){ result *= i; } return result; } int main(void){ int n, m, nPm, mPm; printf("n "); scanf("%d",&n); printf("m "); scanf("%d",&m); nPm = permutation(n,m); mPm = permutation(m,m); printf("nCm=%d\n",nPm / mPm); return 0; } メイン関数が すっきりしましたね! またどこで順列計算を してるかも 分かりやすいです 第5章 関数の作成

  15. 関数の使い道 • プログラムの改良をしやすくする • 同じような文の繰り返しを避ける がありました、他に • 処理のまとまりを分かりやすくする int main(void){ ・・・・ while(true){ ・・・・ ・・・・ ・・・・ ・・・・ ・・・・ } ・・・・ return 0; } シューティングゲームの例 このへんで初期化処理 int main(void){ init(); while(true){ move(); collisionDetection(); draw(); } dispose(); return 0; } このへんで敵を動かす このへんであたり判定 このへんで描画処理 このへんで終了処理 分かりやすい 第5章 関数の作成

  16. プロトタイプ宣言(1) • 関数は使用する場所より上に書かなければならない 関数Aから関数Bを呼び出し、 関数Bから関数Aを呼び出す場合どうする? ここで登場するのがプロトタイプ宣言 プロトタイプ宣言とは 先に関数が存在することだけを宣言する 文法(値を返す関数) 戻り値データ型関数名(引数1データ型,引数2データ型,……) 文法(値を返さない関数) void関数名(引数1データ型,引数2データ型,……) これが使用場所より上にあれば、 関数の実体が下にあっても使用可能 第5章 関数の作成

  17. プロトタイプ宣言(2) #include <stdio.h> int permutation(int,int) int main(void){ int n, m, nPm, mPm; printf("n "); scanf("%d",&n); printf("m "); scanf("%d",&m); nPm = permutation(n,m); mPm = permutation(m,m); printf("nCm=%d\n",nPm / mPm); return 0; } permutation関数が来ることを予告 プロトタイプ宣言 さえ上にあれば使用可 int permutation(intn,int m){ inti , result; i = n; result = 1; for(i = n;i > n - m;i--){ result *= i; } return result; } 第5章 関数の作成

  18. main関数 • 0プログラムが正常終了した • 1 プログラムが異常終了した main関数とはプログラム起動時に呼び出される関数 だから、プログラムはint mainからスタートするのですね 戻り値はint型で以下のように決められています 引数も指定できますが、ここでは説明しません 第5章 関数の作成

  19. ここまでのまとめ • 値を返さない関数 • 値を返さない関数はreturnで強制終了 • 値を返す関数 • 値を返す関数returnで値を返せる • 引数に代入しても呼び出し元の変数には反映されない • プロトタイプ宣言をすれば下にある関数も呼び出せる void 関数名(データ型 引数名 ,データ型 引数…){ } 戻り値データ型関数名(データ型 引数名,データ型 引数…){ } 第5章 関数の作成

  20. 練習問題 問1 先ほどのmCnを求めるプログラムに 次の関数を追加せよ • nの階乗を求める関数 • mCnを求める関数 問2 二つの円の半径、X座標、Y座標から二つの円が 接触しているかを取得する関数を作れ。 接触している場合はtrue、そうでないときはfalseを返せ。 引数は以下の通りにせよ。 (double r1,double x1,double y1,double r2,double x2,double y2) ※r1,r2は円の半径、 x1,x2は円の中心のx座標 y1,y2は円の中心のy座標 第5章 関数の作成

  21. ブロック • ブロックとは{}で囲まれた文の集合のこと • {}は複数の文を1文とみなすことができる • 通常if文など制御文の後には1文しか置けない if( num == 0 ) return 0; if( num == 0 ){ printf("入力が不正です"); return 0; } 1文だけなら {}不要 2文を1文とみなすために {}を付ける ifの後は1文しかこれない 第5章 関数の作成

  22. 変数のスコープ ブロック内で宣言された変数は、 そのブロック内のみで使用することが可能 #include <stdio.h> voidfunc(void){ printf("%d",a); //エラー printf("%d",b); //エラー } int main(void){ int a=1; if( true ){ int b = 2; printf("%d",a); //OK printf("%d",b); //OK } printf("%d",a); //OK printf("%d",b); //エラー return 0; } 使用できる範囲のことを スコープと言います 第5章 関数の作成

  23. 変数の寿命(1) 次のプログラムを実行しよう #include <stdio.h> voidshowZero(boolisInit){ int zero; if( isInit ) zero = 0; printf("%d\n“,zero); } int main(void){ showZero(true); showZero(false); showZero(false); showZero(false); return 0; } 簡単に訳すと 変数zeroを代入せずに使うな! ということです 第5章 関数の作成

  24. 変数の寿命(2) しかし一回目にshowZero関数を呼び出したときに 確かにzeroに0を代入しました 実はブロック内で宣言された変数の値は ブロックが終了した地点で破壊されます もう一度その部分を通っても跡形もありません 一回目にzeroに0を代入しても、 二回目にはその値は破壊されています そこで出てくるのがグローバル変数 第5章 関数の作成

  25. グローバル変数(1) グローバル変数の特徴 • スコープファイル内全て • 寿命プログラムが終了するまで 文法データ型変数名; 文法データ型変数名 =初期値; 書く場所 • 使う場所より上 • 関数の外 ※逆にブロック内の変数をローカル変数と呼ぶ 第5章 関数の作成

  26. グローバル変数(2) 先ほどのプログラムをこのように修正すればうまく動くはずです #include <stdio.h> int zero; voidshowZero(boolisInit){ if( isInit ) zero = 0; printf("%d\n“,zero); } int main(void){ showZero(true); showZero(false); showZero(false); showZero(false); return 0; } グローバル変数があれば 関数にアクセスしたことがあるかも 取得できます。 その機能があれば 引数はいらないですね 第5章 関数の作成

  27. グローバル変数(3) #include <stdio.h> int zero; boolisCalledshowZero = false; voidshowZero(void){ if(!isCalledshowZero){ zero = 0; isCalledshowZero=true; } printf("%d\n",zero); } int main(void){ showZero(); showZero(); showZero(); showZero(); return 0; } isCalledshowZero変数は showZero関数が 呼び出されたことないならfalse そうでなければtrueになります グローバル変数は便利ですが、 多用するとプログラムが 見にくくなります。 最小限の使用に抑えましょう。 第5章 関数の作成

  28. forと変数 forの初期化の場所に変数宣言を書くことができます。 この変数は・・・ スコープfor文ブロック内 + 評価式 + 毎回実行される文 寿命for文終了まで です。 #include<stdio.h> int main(void){ for(inti = 0 ; i <= 10 ; i++){ printf("%d\n", i ); } return 0; } スコープ ここまで寿命 変数のスコープを極力狭くするときれいなプログラムを書ける → このプログラムは最低限のスコープしかない → 今までの方法よりも見やすくなる可能性が高い 第5章 関数の作成

  29. ここまでのまとめ • ローカル変数の寿命はブロックの終了まで • ローカル変数のスコープはブロック内 • グローバル変数の寿命はプログラム終了まで • グローバル変数のスコープはファイル全体 • グローバル変数の宣言は関数の外 第5章 関数の作成

  30. 練習問題 問1 nからmまでのランダム値を返す関数を作れ。 ただし、最初に関数を読んだときのみシードの指定をせよ 問2 1回目その関数を呼び出したときには1を、 2回目その関数を呼び出したときには2を、 3回目その関数を呼び出したときには3を、 n回目その関数を呼び出したときにはnを 返す関数を作成せよ 第5章 関数の作成

More Related