プログラミング基礎演習

鹿児島大学
プログラミング基礎演習
第8回
関数(2) 独立性
半田利弘
鹿児島大学 大学院理工学研究科 物理・宇宙専攻
理化学研究所
関数の独立性
▶ 関数の定義と引用
■
■
引数の順位だけで対応
型が合っていないとまずい
▶ 関数内部の変数は呼び出し元には影響なし
■
関数の内外は引数と戻り値でしか関連しない
理化学研究所
関数の独立性
▶ C言語ではメモリー空間は関数ごとに独立
■
引数は呼び出し元と関数内では別アドレス
 呼び出し時に値をコピーしている
 関数内で変数値を変えても呼び出し元は変わらない
理化学研究所
プログラムで確かめる
▶ List8-2の引数
■
違う変数名でも引数位置が同じなら同じ値になる
#include <stdio.h>
float calc(float xx);
int main(void);
float calc(float price)
/* 割引価格を求める */
{
float waribki;
waribiki=price*0.7;
return(waribki);
}
int main(void)
{
float xx,yy;
xx=10000.0;
yy=calc(xx);
printf("通常価格%.0f円のところ",xx);
printf("今回は特別に%.0f円でご提供\n",yy);理化学研究所
return(0);
}
プログラムで確かめる
▶ 関数内外では同じ変数名でも無関係
#include <stdio.h>
float calc(float xx);
int main(void);
float calc(float price)
/* 割引価格を求める */
{
float waribki;
waribiki=price*0.7;
return(waribki);
}
int main(void)
{
float xx,yy,waribiki;
xx=10000.0;
yy=calc(xx);
waribiki=3.0;
printf("通常価格%.0f円のところ",xx);
printf("今回は特別に%.0f割引で",waribiki);
printf("%.0f円でご提供\n",yy);
理化学研究所
return(0);
}
関数の独立性(advanced)
▶ C言語ではメモリー空間は関数ごとに独立
■
関数が終了すると変数値は保存しない
 保存したい場合は、変数をstaticで宣言する
▶ 自動(auto)変数と静的(static)変数
■
■
auto:ブロックが終了するとOSに返してしまう
static:プログラムが終了するまでメモリを確保
 ソースのファイルが異なると別のメモリに割付られる
■
大域(global)変数というのもあるが使うべきでない
理化学研究所
 頭を使えば99%回避できる
プログラムで確かめる
 List8-3改2
#include <stdio.h>
void print_graph(int xx);
int main(void);
void print_graph(int xx)
/* 棒グラフを*で書く */
{
int ii;
printf("ii=%d\n",ii);
for(ii=0;ii<xx;ii++) {
printf("*");
}
printf("\n");
return;
}
int main(void)
{
int xx:
xx=10;
print_graph(xx);
print_graph(5);
return(0);
}
理化学研究所
プログラムで確かめる
 List8-3改3
#include <stdio.h>
void print_graph(int xx);
int main(void);
void print_graph(int xx)
/* 棒グラフを*で書く */
{
static int ii;
printf("ii=%d\n",ii);
for(ii=0;ii<xx;ii++) {
printf("*");
}
printf("\n");
return;
}
関数が終わっても覚えておく
int main(void)
{
int xx:
xx=10;
print_graph(xx);
print_graph(5);
return(0);
}
理化学研究所
staticはどんなときに使う?(1)
▶ 呼び出した回数で内容が変わる時
#include <stdio.h>
void print_graph(int xx);
int main(void);
void print_graph(int xx)
{
static nankai=0;
int ii; char mark;
if(nankai>1) mark='o';
else mark='*';
for(ii=0;ii<xx;ii++) {
printf("%c",mark);
}
printf("\n");
nankai++;
return;
}
int main(void)
{
int xx:
xx=10;
print_graph(xx);
print_graph(xx*2);
print_graph(5);
return(0);
}
理化学研究所
staticはどんなときに使う?(2)
▶ 前の結果を次の呼び出しで使いたい時
#include <stdio.h>
void print_graph(int xx);
int main(void);
void print_graph(int xx)
{
static int last_xx=0;
int ii; char mark;
for(ii=0;ii<xx;ii++) {
printf("%c",mark);
}
printf("\n");
if(last_xx>5) mark='o';
else mark='*‘;
last_xx=xx;
return;
}
int main(void)
{
int xx:
xx=10;
print_graph(xx);
print_graph(xx*2);
print_graph(5);
return(0);
}
理化学研究所
複数変数の関数
■
List8-4(教科書p.192)
#include <stdio.h>
int GetPower(int xx, int nn);
int main(void);
int GetPower(int xx, int nn)
/* 整数のべき乗を得る */
{
int ii, jj=1;
for(ii=0;ii<nn;ii++) {
yy=yy*xx;
}
return(yy);
}
引数とその型宣言を「,」区切
りで並べて書く
int main(void)
{
int zz;
zz=GetPower(8,2);
printf("%d\n",zz);
return(0);
}
引数を「,」区切り
で並べて書く
理化学研究所
main関数
▶ 1つのプログラムの最上位となる関数
▶ 先頭のおまじない int main(void)
■
■
■
main関数の定義宣言だった
「void」は引数がないことの明示
実は、int main(int argc, char **argv)とすべき
 「char **」ってなに?→後でね
▶ 呼び出し元はOS
理化学研究所
ゲームに必須の関数
▶ 乱数(でたらめな数)を返す、サイコロを振る
▶ int rand(void);
■
■
■
#include <stdlib.h>
“種”から乱数もどきを作る
0~RAND_MAXの間の整数値
 RAND_MAXの値はコンパイラーによる
 必要な最大値で割ったあまりを使う
理化学研究所
乱数発生関数
▶ 使用例 ListA-1.c
#include <stdio.h>
#include <stdlib.h>
int main(void);
int main(void)
{
saidaiで割って切り捨て
int xx, yy, saidai=10;
saidaiで割った最少倍数
xx=rand();
printf("xx=%d\n",xx);
yy=(xx/saidai)*saidai;
yy=xx-yy;
printf("yy=%d\n",yy);
return(0);
}
理化学研究所
saidaiで割った余り
疑似乱数の実行
▶ ListA-1.cをコンパイルして実行
▶ あれ、いつも同じ数…
理化学研究所
疑似乱数の“疑似”とは
▶ いつでも同じ種だと同じ順に数値が出る
■
“種”を変えないといつも同じ
▶ void srand(unsigned int ii);
■
■
■
#include <stdlib.h>
rand()に種seedを与える関数
種はどうやって与えても良い
 プレーヤーの年齢
 プレーヤーの名前の文字コードとか
 ゲームを始めた時刻とか
理化学研究所
現在時刻を得る関数
▶ time_t time(void);
■
■
#include <time.h>
現在時刻を返す
 値:1970年1月1日0時からの通算秒数
 time_tがlong型だと、そろそろ桁あふれするので注意
 2038年問題
理化学研究所
現在時刻を疑似乱数の種に…
▶ time()の戻り値を疑似乱数の種にする
▶ main関数の先頭近くで
■
srand((unsigned int)time());
▶ を実行すれば良い。
理化学研究所
乱数発生
▶ 改良版ListA-2.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int std_rand(int saidai);
int main(void);
int std_rand(int saidai)
{
int xx, yy;
xx=rand();
yy=(xx/saidai)*saidai;
yy=xx-yy;
return(yy);
}
int main(void)
{
int xx, ii;
/* 乱数の初期化 */
srand((unsigned int)time(NULL));
for(ii=0;ii<15;ii++) {
xx=std_rand(10);
printf("%d, ",xx);
}
printf("\n");
return(0);
}
理化学研究所
期末課題
▶ 最終回の授業で自作ゲームの紹介
■
■
■
■
■
個人またはチームごとで1作、1チーム1~3名
全員、いずれかのチームに所属すること
C言語で作成する
主な動作とプログラムで工夫した部分の解説
発表は5分、質疑応答3分を想定
理化学研究所