関数
現在までの授業では,100行にも満たないとても短いプログラムしか書いていませんが,今後の課題では数百行や数千行というプログラムを書かなければいけないことが出てきます.このようなプログラムでは,どの部分でどのような処理が行われているのか,ということが把握しにくくなり,結果としてバグ(プログラムの間違い)だらけのプログラムになりやすくなってしまいます.
そこで,関数を利用して,関連した処理(例えば,累乗を計算する処理や総和を計算する処理など)を1つのまとまりとしてまとめることで,プログラムをコンパクトにし,どの部分でどの処理が行われているかを分かりやすくします.
関数を書いてプログラムをまとめる利点は,プログラムがコンパクトになり処理が把握しやすくなるだけでなく,
- 同じような処理を複数回記述する手間を省ける
- 各機能毎に関数をまとめておくことでプログラムの修正が容易になる(どの部分を直せば良いのか分かりやすい)
と言った点があげられます.
ですので,皆さんにはぜひmain文が非常に長いものにならないように,関数をうまく活用して行くことをお勧めします.
では,「具体的にはどのように関数を書くのか」と言う点について説明して行きたいと思います.関数の書き方についての詳細は授業ページを見ていただいて,ここでは基本的な書き方について簡単に説明したいと思います.
戻り値の型 関数名(引数){ ... 関数内での処理; ... return文; }
この書き方が基本です.
例として,x+yの値を計算するプログラムを考えます(x,yは整数とする).
#include <stdio.h> int func(int x, int y){ return x + y; } int main(void){ int x_input = 1; int y_input = 2; int sum = wa(x_input, y_input); printf("sum = %d\n", sum); return 0; }
この関数の処理の流れは,
- x_input,y_inputのそれぞれの変数に値 1,2を代入
- 変数sumに関数waで書いた処理(x + yのこと,具体的に何の値を足せば良いのかを関数に教えるために引数にx_input, y_inputをとる)を実行した時の戻り値を返す
- 最後にsumの値を画面に出力
という順番で行われます.
授業では,このときの関数とメイン文で同じ変数を使っていいのか?などの質問を多く受けましたが,とりあえずは,「{ }」の中で同じ変数が使われていなければ大丈夫である.と覚えておいてください.
以上で,今回の授業のおさらいは終わりです.
以下,課題の考え方についてです.
5組
1.キーボードから整数 n を入力し,1 から n までの和,∑n および二乗和 ∑n2 を計算し,画面に表示せよ.
この課題のポイントは,
①1からnまでの繰り返し計算
②繰り返しの終点が計算開始初期からわかっている
です.和の計算に関しては,授業内練習問題のQ2にてプログラム済みですので,もうできると思います.
また,繰り返し計算をどのループ(for, while)を使っても可能なので,各々試してみてください.強いて言うなら,②があるので,forループの方がやりやすいかも...?
2.フィボナッチの数列 ak = ak-1 + ak-2 ,a1 = 1, a2 = 1 の第n項までを画面に表示せよ.nはキーボードから入力する.
実行例: n= 10 a1 = 1 a2 = 1 a3 = 2 a4 = 3 a5 = 5 a6 = 8 a7 = 13 a8 = 21 a9 = 34 a10 = 55
この課題のポイントは,
①各変数ak,ak-1,ak-2の計算順番です.例えば,3つの変数をそれぞれ用意しておきak = ak-1 + ak-2を計算し,その後ak-1とak-2の値を更新していくのと,更新を先に行ってから計算処理をするのでは,全く違う値が得られます.果たしてどの順番が正しいのか,混乱するとは思いますが,よく考えながらプログラムしましょう.
3.for
文のネストを利用して,以下のように - と | が交互に出現する表を画面に表示しなさい
|-|-|-|-|-|- -|-|-|-|-|-| |-|-|-|-|-|- -|-|-|-|-|-| |-|-|-|-|-|- -|-|-|-|-|-|
この課題のポイントは,
①6×12の行列の形
②|と-が交互
です.①の形は,授業内練習課題のQ4でもやりましたね.②は,考え方はいくつかあると思います.for文のカウンタ変数の奇偶による条件分岐,四則演算による条件分岐etc...
ぜひ,TAも感心する処理方法を考えてプログラムしてみてください!
4. while
文を用い, 0 < x < 2π の範囲で,f( x ) = cos( x ) の最初の極小値と,その時のxの値を求め,画面に表示せよ. (もちろん答えは x = π のとき,-1 である)
#include <stdio.h>
#include <math.h> /* cos 関数の使用に必要 */
int main(void)
{
float x;
float dx = ????;
while( ??? ) {
if(???)
break;
x += dx;
}
printf(...); /* 結果の表示 */
return 0;
}
この課題は,本ブログ「第4回 制御文2」内の課題の考え方6組2問目での考え方と一緒です.そちらと授業ページのヒントを参考にしましょう.
5.1から1000までの自然数において,(a)入力した列数で改行して表示し,(b)その際に任意の自然数の倍数を伏せ字にするプログラムを作成せよ.
実行例 : 改行する列数 = 7 伏字にするのは = 4 1| 2| 3|-----| 5| 6| 7| -----| 9| 10| 11|-----| 13| 14| 15|-----| 17| 18| 19|-----| 21| (中略) 967|-----| 969| 970| 971|-----| 973| 974| 975|-----| 977| 978| 979|-----| 981| 982| 983|-----| 985| 986| 987| -----| 989| 990| 991|-----| 993| 994| 995|-----| 997| 998| 999|-----|
この課題のポイントは,
①表示が行列の形
②列数は入力した値で変化
③入力にて指定した自然数の倍数に対する処理
です.①は課題3と同じなのですが,列数の条件は入力された値によって変わります(②).ネストさせたループの列数を指定する条件判定部に気をつけてプロ グラムしてみましょう.③はこれまでもやってきた条件分岐の処理です.任意の数nの倍数ということは,言い換えるとnで割った余りが0というのは,授業中 に先生が何度も仰っていましたね.この課題は①,②ができたことを確認できたら,③を追加しましょう.1つの問題の中に複数の独立した問題がある場合 (今回でいうと,任意の列数の行列表示と任意の数字の倍数の伏字化),片方だけでうまく実行できることを確認できた後に全部を1つにすることで,エラーが出た際にバグ部分を見つけやすくなります.
6組
1. 直角三角形の短辺2つの長さ(a,b)を入力すると,長辺の長さ(c)を返す関数を作りましょう. a,bの値はそれぞれキーボードから入力します.
この問題では,計算処理は関数で行い,main関数では,関数を呼び出す前処理や結果の表示だけ行います.
具体的に関数内で行う計算処理は三平方の定理を利用することです.
またこの問題では,math.hというヘッダファイルをインクルードすることで平方根の計算を非常に簡単に行うことが可能です.
プログラムの例としては,
#include <stdio.h> #include <math.h> float calculate_triangle(float a, float b){ return sqrt(平方根の中身の計算); }
となります.このプログラムの中身の計算は,上記で説明した三平方の定理を利用した計算式です.
2. QUIZの5番目の問題は,1から3までの3個の2乗和を求めました. このプログラムを改良して,1からNまでの2乗和を求めるプログラムにしてください. このとき,Nの値は,scanf()関数で与えられるようにしてください.
この問題は,QUIZ5で作成したjijo関数をそのまま流用し,wa関数を少しだけ修正することで簡単にプログラムを解くことが出来ます.
それぞれQUIZでは
//二乗を計算する関数 int jijo(int x){ return x*x; } //3つの値の和を計算する関数 int wa(int a, int b, int c){ return a + b + c; }
となっていました.
QUIZと今回の問題の変更点は,「1から3までの3個の2乗和を求める」と「1からNまでの2乗和を求める」と言う点です.ここで,注目してもらいたい点は,「1からNまで」というフレーズです.この部分から制御文の授業で学んだ,「繰り返し」が使えるということに気づいてほしいですね.
このことに築くことが出来たならば,後は引数を繰り返し回数の上限であるNとするような関数を作成します.
解答例のヒントとしては
int wa2(int N){ for(int i=0;i<N;i++){ 2乗和を計算する処理(QUIZで作成したjijo関数を利用しましょう); } return 1からNまでの2乗和; }
3. 速度0で静止しているロケットに点火してロケットを打ち上げます.ロケットの質量を,推力が
で一定だとしたとき, 打ち上げから時間t秒後の速度
を求める関数を作って下さい.引数は
で,戻り値が
です.
この問題は,
の数式を利用できるので,この数式をそのまま関数とします.
また引数がm, F, tということから加速度aを求めるために
を利用してください.
このことをふまえて関数を作成すると,解答の一例として以下のような関数が作成できると思います.
float velocity(float F, float m, int t){ 加速度aを求める計算処理; return 上記の加速度を利用した速度を計算する処理; }
この解答例では,推力Fと質量mは少数でも計算可能なようにfloat型の変数で定義し,時間tは整数しか入力されないと考えint型としました.さらに,計算される速度も小数になり得ると考え,float型です.
ここのそれぞれの変数型は,きちんと速度の計算を行うことが出来れば,個人の自由に変更していただいて結構です.
授業ページの問題文”~する関数を作ってください”とありますが,もちろんmain関数も必要です.
すべてのプログラムにおいて,きちんとコンパイル(リンクまで)が通る形で提出してください.
繰り返しでくどいようですが,まだ,ファイルの命名規則が守られてない人がいます. ~.zip.zipになっていないかなど,きちんと確認をしてから提出するようにお願いします.
では,皆さん課題をがんばってください.