• 検索結果がありません。

スライド 1

N/A
N/A
Protected

Academic year: 2021

シェア "スライド 1"

Copied!
30
0
0

読み込み中.... (全文を見る)

全文

(1)

第5章 関数の作成

今まで使ってばっかりだった関数

(2)

値を返さない関数(1)

値を返さない関数とは、式や引数に含めることができない関数

たとえば、

srand(time(NULL))

+ 1

とは書きませんよね

ここでは

srand関数

→値を返さない関数

time関数

→値を返す関数

です

(3)

値を返さない関数(2)

#include <stdio.h> int main(void){ double height,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;

エラーが起きた時の

メッセージを変えたい!!

数か所変えなければならない

マクロ使

う?

エラーが起きた時に

音が出るように変えたい!!

マクロでは対応不可

数か所変えなければならない

こうなった時のために

エラーを表示する関数

作ろう

(4)

値を返さない関数(3)

値を返さない、引数がない関数の定義

文法

void

関数名

(void){

関数が呼び出時に実行する文1;

文2;・・・

}

main関数など関数の外に書く

使いたい場所より上に書く

注意事項

関数を作るといっても今までの関数や文法などの

組み合わせで新たな関数を作るだけです。

未知の関数を作るわけではなく

決して難しくないので安心してください

(5)

値を返さない関数(3)

bmi=weight/height/height; printf("BMI %lf¥n",bmi); return 0;

} #include <stdio.h>

void showErrorMessage(void){ printf("エラー¥n"); } int main(void){ double height,weight,bmi; printf("身長(m) "); scanf("%lf",&height); if(height <= 0){ showErrorMessage(); return 0; } printf("体重(kg) "); scanf("%lf",&weight); if(weight <= 0){ showErrorMessage(); return 0;

エラーメッセージを

表示するだけの

showErrorMessage関数が

できました

(6)

引数(1)

ただ「エラー」と表示させるだけではなく

何がエラーなのかも表示したいですよね

ここで活躍するのが、そう、

引数

です

値を返さない、引数のある関数の定義

文法

void

関数名

(

引数1のデータ型 引数1の名前

,

引数2のデータ型 引数2の名前

,

・・・・){

関数が呼び出時に実行する文1;

文2;・・・

}

改行は普通しない

(7)

引数(2)

文法

void

関数名

(

引数1のデータ型 引数1の名前

,

引数2のデータ型 引数2の名前

,

・・・・){

関数が呼び出時に実行する文1;

文2;・・・

}

たとえば、名前bの

int

型を引数に持つ関数Aがあるとします

void A(int b){ ・・・ } int main(void){ A(100); return 0; }

 A関数内ではbは変数のように扱える

 代入、参照が可能

 bの初期値はmain関数で指定した100

(8)

引数(3)

#include <stdio.h>

//causeが0なら身長,1なら体重が不正

void showErrorMessage(int cause){

if(cause == 0){ printf("身長が不正¥n"); }else if(cause == 1){ printf("体重が不正¥n"); } printf(“エラー¥n"); } int main(void){ double height,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の取りうる値を

マクロにすべきですが、スペースがないので お許しください・・・

(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; }

Cには

影響しない

main関数

a関数

0

c

0

b

1

b

0

c

0

c

int

c = 0;

a(c);

b = 1;

(10)

return文(1)

showErrorMessage関数ですが、

引数が0,1以外の時は関数を強制終了させたいですね

文法

return;

値を返さない関数では

return

文を使って関数を強制終了できます

では先ほどのプログラムを改造しましょう

(11)

return文(2)

#include <stdio.h>

void showErrorMessage(int cause){ if(cause == 0){ printf("身長が不正¥n"); }else if(cause == 1){ printf("体重が不正¥n"); }else{ return; } printf(“エラー¥n"); } int main(void){ double height,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;

}

実行されない文を書くのは無駄だと思うかも知れませんが、

ひょっとしたら引数の指定を間違えるかもしれません

(12)

値を返す関数(1)

#include <stdio.h> int main(void){ int n, 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; } m n

C

を求めるプログラム

左は

m m m n m n

P

P

C

より、

s r

P

を求める関数を作れば

すっきり書けるのではないか

同じような処理を複数回書くのは

プログラミングでは嫌われる

(13)

値を返す関数(2)

値を返さない、引数のある関数の定義

文法

戻り値データ型 関数名

(

引数1のデータ型 引数1の名前

,

引数2のデータ型 引数2の名前

,

・・・・){

関数が呼び出時に実行する文1;

文2;・・・

}

改行は普通しない

また、値を返す文も必要ですね。

return

文が、値を返し、関数を強制終了します

文法

return

戻り値

;

値を返さない関数の時とは違い、

値を返すという役割があるので注意しよう!

引数がない場合は

void

(14)

値を返す関数(3)

#include <stdio.h>

int permutation(int n,int m){ int i , 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;

メイン関数が

すっきりしましたね!

またどこで順列計算を

してるかも

分かりやすいです

(15)

関数の使い道

プログラムの改良をしやすくする

同じような文の繰り返しを避ける

処理のまとまりを分かりやすくする

がありました、他に

int main(void){ ・・・・ while(true){ ・・・・ ・・・・ ・・・・ ・・・・ ・・・・ } ・・・・ return 0; このへんで初期化処理 このへんで敵を動かす このへんであたり判定 このへんで描画処理 このへんで終了処理 int main(void){ init(); while(true){ move(); collisionDetection(); draw(); } dispose(); return 0;

分かりやすい

シューティングゲームの例

(16)

プロトタイプ宣言(1)

関数は使用する場所より上に書かなければならない

関数Aから関数Bを呼び出し、

関数Bから関数Aを呼び出す場合どうする?

ここで登場するのが

プロトタイプ宣言

プロトタイプ宣言とは

先に関数が存在することだけを宣言する

文法

(値を返す関数)

戻り値データ型 関数名

(

引数1データ型

,

引数2データ型

,……)

文法

(値を返さない関数)

void

関数名

(

引数1データ型

,

引数2データ型

,……)

これが使用場所より上にあれば、

関数の実体が下にあっても使用可能

(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;

}

int permutation(int n,int m){ int i , result;

i = n;

result = 1;

for(i = n;i > n - m;i--){ result *= i; } return result;

permutation関数が来る

ことを予告

プロトタイプ宣言

さえ上にあれば使用可

(18)

main関数

main関数とはプログラム起動時に呼び出される関数

だから、プログラムは

int

mainからスタートするのですね

0 プログラムが正常終了した

1 プログラムが異常終了した

戻り値は

int

型で以下のように決められています

引数も指定できますが、ここでは説明しません

(19)

ここまでのまとめ

値を返さない関数

値を返さない関数は

return

で強制終了

値を返す関数

値を返す関数

return

で値を返せる

引数に代入しても呼び出し元の変数には反映されない

プロトタイプ宣言をすれば下にある関数も呼び出せる

void 関数名(データ型 引数名 ,データ型 引数…){

}

戻り値データ型 関数名(データ型 引数名,データ型 引数…){

}

(20)

練習問題

先ほどのmCnを求めるプログラムに

次の関数を追加せよ

nの階乗を求める関数

mCnを求める関数

問1

問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座標

(21)

ブロック

ブロックとは{}で囲まれた文の集合のこと

{}は複数の文を1文とみなすことができる

通常

if

文など制御文の後には1文しか置けない

if( num == 0 ) return 0; if( num == 0 ){ printf("入力が不正です"); return 0; }

1文だけなら

{}不要

2文を1文とみなすために

{}を付ける

ifの後は1文しかこれない

(22)

変数のスコープ

ブロック内で宣言された変数は、

そのブロック内のみで使用することが可能

#include <stdio.h> void func(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; }

使用できる範囲のことを

(23)

変数の寿命(1)

#include <stdio.h>

void showZero(bool isInit){ int zero; if( isInit ) zero = 0; printf("%d¥n“,zero); } int main(void){ showZero(true); showZero(false); showZero(false); showZero(false); return 0; }

次のプログラムを実行しよう

簡単に訳すと

変数zeroを代入せずに使うな!

ということです

(24)

変数の寿命(2)

しかし一回目にshowZero関数を呼び出したときに

確かにzeroに0を代入しました

実はブロック内で宣言された変数の値は

ブロックが終了した地点で破壊されます

もう一度その部分を通っても跡形もありません

一回目にzeroに0を代入しても、

二回目にはその値は破壊されています

そこで出てくるのが

グローバル変数

(25)

書く場所

グローバル変数(1)

グローバル変数の特徴

スコープ

ファイル内全て

寿命

プログラムが終了するまで

文法

データ型

変数名

;

文法

データ型

変数名

=

初期値

;

使う場所より上

関数の

※逆にブロック内の変数を

ローカル変数

と呼ぶ

(26)

グローバル変数(2)

#include <stdio.h>

int zero;

void showZero(bool isInit){ if( isInit ) zero = 0; printf("%d¥n“,zero); } int main(void){ showZero(true); showZero(false); showZero(false); showZero(false); return 0; }

先ほどのプログラムをこのように修正すればうまく動くはずです

グローバル変数があれば

関数にアクセスしたことがあるかも

取得できます。

その機能があれば

引数はいらないですね

(27)

グローバル変数(3)

#include <stdio.h>

int zero;

bool isCalledshowZero = false;

void showZero(void){ if(!isCalledshowZero){ zero = 0; isCalledshowZero=true; } printf("%d¥n",zero); } int main(void){ showZero(); showZero(); showZero(); showZero(); return 0; }

isCalledshowZero変数は

showZero関数が

呼び出されたことないなら

false

そうでなければ

true

になります

グローバル変数は便利ですが、

多用するとプログラムが

見にくくなります。

最小限の使用に抑えましょう。

(28)

forと変数

for

の初期化の場所に変数宣言を書くことができます。

この変数は・・・

スコープ

for

文ブロック内 + 評価式

+ 毎回実行される文

寿命

for

文終了まで

です。

#include <stdio.h> int main(void){ for(int i = 0 ; i <= 10 ; i++){ printf("%d¥n", i ); } return 0; }

スコープ

ここまで寿命

変数のスコープを極力狭くするときれいなプログラムを書ける

→ このプログラムは最低限のスコープしかない

→ 今までの方法よりも見やすくなる可能性が高い

(29)

ここまでのまとめ

ローカル変数の寿命はブロックの終了まで

ローカル変数のスコープはブロック内

グローバル変数の寿命はプログラム終了まで

グローバル変数のスコープはファイル全体

グローバル変数の宣言は関数の外

(30)

練習問題

nからmまでのランダム値を返す関数を作れ。

ただし、最初に関数を読んだときのみシードの

指定をせよ

問1

問2

1回目その関数を呼び出したときには1を、

2回目その関数を呼び出したときには2を、

3回目その関数を呼び出したときには3を、

n回目その関数を呼び出したときにはnを

返す関数を作成せよ

参照

関連したドキュメント

、肩 かた 深 ふかさ を掛け合わせて、ある定数で 割り、積石数を算出する近似計算法が 使われるようになりました。この定数は船

Sino-Japanese compounds, I demonstrated that the accentual pattern of a Sino-Japanese compound is determined by the mora length of the second element of the compound... If the

入学願書✔票に記載のある金融機関の本・支店から振り込む場合は手数料は不要です。その他の金融機

断するだけではなく︑遺言者の真意を探求すべきものであ

いてもらう権利﹂に関するものである︒また︑多数意見は本件の争点を歪曲した︒というのは︑第一に︑多数意見は

ヒット数が 10 以上の場合は、ヒットした中からシステムがランダムに 10 問抽出して 出題します。8.

表 2.1-1 に米国の NRC に承認された AOO,ATWS,安定性,LOCA に関する主な LTR を示す。No.1 から No.5 は AOO または ATWS に関する LTR を,No.6 から No.9 は安定性に 関する

イ  日常生活や社会で数学を利用する活動  ウ  数学的な表現を用いて,根拠を明らかにし筋.