PowerPoint プレゼンテーション

コンピュータ基礎実験 第10回
コンピュータープログラミング
(C言語)(7)
1.繰り返し処理、配列(復習)
2.乱数
繰り返し処理(復習)
コンピュータでは、少しずつ条件を変えながら同
じ処理を繰り返す状況がよくでてきます。
C言語では、繰り返し処理を行うために「for文」、
「while文」が用意されています。
「for文」:「初期値」を与え、与えられた条件を満たし
ている間、同じ処理を繰り返す
「while文」: 特に初期値を設定せず、与えられた条件
を満たしている間、同じ処理を繰り返す
繰り返し処理
For文
for (初期値の式; 条件式; ループの終わりに実行する式){
文
}
While文
While文
(初回も条件チェック)
while (式){
文
}
do~while文
(初回は条件チェック無)
do{
文
} while (式);
前回課題9-6:ex9-6.c
前回課題9-6:自然対数の底e(=2.71828…)は次の無限級数で与えられ
る。

1 1 1 1
1
1
e   



1 1 2 1 3  2 1 4  3  2 1
i 0 i!
上の無限級数の初めのn項目までを計算するプログラムを作成せよ。
このとき、小数点以下10桁(”%.10f”)で出力せよ。
(→ ex9-6.c)
WEB上でeの値を調べ、n=1, 5, 10, 20について自分のプログラムで
計算し、収束する様子を確認せよ。(double変数を使用せよ)
注)「0!=」1です。
4
前回課題9-6解答例
#include <stdio.h>
int main(void)
{
int i,n;
double x=1, sum=0;
scanf("%d",&n);
for(i=1;i<=n;i++){
if(i!=1){
x*=(double)(i-1);
}
sum+=1/x;
}
printf("e=%.10f\n",sum);
n!を記憶する変数として「x」を宣言
n!はn=0の時、特殊なので扱いを別にする
n=0のとき「n!=0!=1」
n!は前回ループの時(n-1)!を求めてあるの
で前回の値にn(=i-1)を掛ければよい
変数「sum」にどんどん1/n!を足していく
初期化「sum=0」を忘れるな!
return 0;
}
5
配列(復習)
「繰り返し処理」とともに用いると、非常に便利な
機能が「配列」という機能です。
「配列」は、ベクトルや行列の成分のように、複
数の数字の組み合わせを「添え字」を用いて表
す「変数」(数字を記録する箱)のセットです。
a[0]、a[1]、a[2]…のようにカギ括弧を使う。添え字は0から
b[0][0]、b[0][1]…: 添え字が2変数
C[0][0][0]、c[0][0][1]…:添え字が3変数
文字列も配列を利用して扱います(New)
配列の使用法
 配列の宣言
int a[12]; float b[35]; double c[10]; など
[ ]内は配列のメンバー数
 初期値の代入
int a[3]={3,-2,1}; 宣言時に初期値を代入できる
int a[]={3,-2,1}; 初期値代入の場合はメンバー数省略可
宣言時以外ではいっぺんに代入するのは不可能
 配列の参照
[ ]内に参照したい番号を書いて参照する(0始まり)
int a[3]={1,-2,3}; のとき a[1]には「-2」が記憶されている
文字列
文字列はchar型変数の配列を利用して実現
しています
char h[]=”Hello world!\n”; *
アドレス(箱番号) 0
値
325
1
2
2441
-523
3
’H’
4
’e’
5
’l’
6
’l’
7
’o’
‥‥
’\n’まで
h ⇒3
h[0] ⇒ ’H’
h[1] ⇒ ’e’
「h[]」と名付けた
*配列メンバー数は初期値代入のため省略されている
メンバー数は14個、 「\n」の後に文字列の終わりを示す「終
端文字」が加えられる
例題10-1文字列と配列:ex10-1.c
#include <stdio.h>
int main(void)
{
char h[]=”Hello world!\n”;
int i;
printf(”%s”,h);
printf(”文字列の先頭アドレスは%uです。\n”,(unsigned int)h);
for(i=0; i<13; i++){
printf(”%d番目の文字は、「%c」です。\n”,i,h[i]);
}
return 0;
}
9
例題10-2文字列の利用:dq2-1.c
#include <stdio.h>
#include <unistd.h>
printf("%s%s",quest1,yesno);/*旅?*/
scanf("%d",&a);
if(a==1){
sleep(2);
printf("%s%s%s%s",name_m1,event1,quest2,yesno);/*メタル出現*/
scanf("%d",&a);
if(a==1){ /* メタルと戦う */
battle1(name,name_m1);
}
else{ /* メタルと戦わない */
printf("%s",event2);
sleep(2);
printf("%s%s",name,event3);
sleep(2);
}
}
else{
printf("%s%s",name,event3);
sleep(2);
}
printf("%s%s%s%s",king1,name,king2,king4);
return 0;
int intromusic(void);
int battle1(char name[], char name_monster[]);
int main(void)
{
char name[20];
char king1[]="「王様」ゆうしゃ ";
char king2[]=" よ ";
char king3[]="りゅうおうを たおすのじゃ\n";
char king4[]="しんでしまうとはなさけない\n";
char quest1[]="たびにでる?\n";
char quest2[]="たたかう?\n";
char quest3[]="右へいく?\n";
char name_m1[]="メタルスライム";
char name_m2[]="キラーマジンガー";
char event1[]="があらわれた\n";
char event2[]="そのあと なにもであいませんでした\n\n";
char event3[]="はへいぼんないっしょうをおえ、なくなりました\n\n";
char yesno[]="1. はい 2. いいえ\n";
}
int i,a;
intromusic();
printf("名前を入れてください: ");
scanf("%s",name); printf("\n\n");
printf("%s%s%s%s",king1,name,king2,king3);
10
例題10-2文字列の利用:dq2-2.c
#include <stdio.h>
#include <unistd.h>
int battle1(char name[], char name_monster[])
{
printf("ちゃららっ\n\n");
sleep(1);
printf("ゆうしゃ %s のこうげき\n",name);
sleep(2);
printf("%sに25のダメージ\n\n",name_monster);
sleep(2);
printf("%sのこうげき\n",name_monster);
sleep(2);
printf("ゆうしゃ %s に35のダメージ\n\n",name);
sleep(2);
printf("ゆうしゃ %s はしんでしまった\n\n",name);
sleep(2);
return 0;
}
int intromusic(void)
{
char m1[]="ちゃーちゃ";
char m2[]="ちゃちゃちゃ";
char m3[]="ちゃ";
char m4[]="ちゃん";
printf("%s %s%s %s %s %s\n",m1,m2,m3,m2,m2,m3);
sleep(2);
printf("%s %s %s\n\n",m1,m2,m4);
sleep(3);
return 0;
}
11
乱数(random number)
コンピューターでは、サイコロの様に毎回ランダ
ムに変化する数字を生成することができます
毎回ランダムに変化する数を「乱数」といいます
C言語では乱数を生成する関数として「rand()」
関数が標準で用意されています
「rand()」はC言語が開発された時から用意されているので、
設計が古く、ランダムさの性能がよくありません
必ず用意されているとは限りませんが、もし「random()」関
数が用意されている場合はこちらを使った方がよい
■ 乱数の出し方
/* 乱数 ex10-3.c */
#include <stdio.h>
#include <stdlib.h>
「rand()」関数が宣言
されている
[ 出力例 ]
int main(void)
{
int i, rn ;
for(i=0;i<10;i++){
rn=rand();
printf("%d¥n",rn);
}
return 0;
}
33613
564950497
1097816498
1969887315
1404212
940422543
202055087
768218108
770072198
1866991770
13
「rand()」関数の性質
プログラムを繰り返すと毎回同じ乱数の列が得
られる
本当の乱数ではない!「疑似乱数」
最小値「0」、最大値「RAND_MAX」の整数
「RAND_MAX」がいくつなのかは処理系に依存
printf(”%ld\n”,(long)RAND_MAX);で調べられる
「rand()」関数を使うには「#include <stdlib.h>」が
必要
プログラム実行毎に、異なる乱数の列を発生さ
せたいときには、「srand(s)」関数を実行する
「srand(s)」関数と関数の系列
 「s」の値(整数型、seedと呼ぶ)が異なると、乱数列
が異なる→例題ex10-4.c
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int s,i,rn;
srand(0); printf("seed=0\n"); /* seedが0 */
for(i=0; i<10; i++){
rn=rand();
printf("%d\n",rn);
}
printf("\n");
srand(1); printf("seed=1\n"); /* seedが1 */
for(i=0; i<10; i++){
rn=rand();
printf("%d\n",rn);
}
printf("seed sを入力: ");
scanf("%d",&s);
srand(s);
printf("\n");
printf("seed=%d\n",s);
for(i=0; i<10; i++){
rn=rand();
printf("%d\n",rn);
}
return 0;
}
テクニック
srand((unsigned int)time(NULL));
とすると手で入力しなくてよい
(#include <time.h>が必要)
範囲の決まった乱数の生成
「rand()」は0~RAND_MAXの範囲の乱数を生成
0~9の範囲の乱数を生成するには?
「剰余%」を利用!
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
int i,r;
srand((unsigned int)time(NULL));
for(i=0; i<10; i++){
r=rand()%10; /* 0~9の間の乱数、10で割ったあまりは0~9の範囲 */
printf(”%d\n”,r);
}
return 0;
}
例題10-5ランダムなモンスター出現:dq2-1b.c
(50%の確率で、メタルスライムかキラーマジンガーが出現)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
printf("%s%s",quest1,yesno);/*旅?*/
scanf("%d",&a);
if(a==1){
sleep(2);
srand((unsigned int)time(NULL)); m=rand()%2;
if(m==0){
printf("%s%s%s%s",name_m1,event1,quest2,yesno);/*M出現*/
}
else{
printf("%s%s%s%s",name_m2,event1,quest2,yesno);/*M出現*/
}
scanf("%d",&a);
if(a==1){ /* メタルと戦う */
if(m==0){
battle1(name,name_m1);
}
else{
battle1(name,name_m2);
}
}
else{ /* メタルと戦わない */
printf("%s",event2);
sleep(2);
printf(”%s%s",name,event3);
sleep(2);
}
}
else{
printf(”%s%s",name,event3);
sleep(2);
}
printf("%s%s%s%s",king1,name,king2,king4);
17
return 0;
int intromusic(void);
int battle1(char name[], char name_monster[]);
int main(void)
{
char name[20];
char king1[]="「王様」ゆうしゃ ";
char king2[]=" よ ";
char king3[]="りゅうおうを たおすのじゃ\n";
char king4[]="しんでしまうとはなさけない\n";
char quest1[]="たびにでる?\n";
char quest2[]="たたかう?\n";
char quest3[]="右へいく?\n";
char name_m1[]="メタルスライム";
char name_m2[]="キラーマジンガー";
char event1[]="があらわれた\n";
char event2[]="そのあと なにもであいませんでした\n\n";
char event3[]=”はへいぼんないっしょうをおえ、なくなりました\n\n";
char yesno[]="1. はい 2. いいえ\n";
int i,a,m;
intromusic();
printf("名前を入れてください: ");
scanf("%s",name); printf("\n\n");
printf("%s%s%s%s",king1,name,king2,king3);
}
課題10-6: 丁半ゲーム(お金をかけてはいけません)
サイコロを2個ふり、目の合計が偶数なら「丁(ちょう)」奇数な
ら「半(はん)」とする。丁か半かを予測するゲームを行うとき、
2個のサイコロの代わりとなるプログラムを作成せよ。
( ex10-6.c )
$ ./ex10-6.exe
サイコロの目は3と2です
3-2の半です
課題 10-7
0から9までの乱数をN個発生させ,それぞれの数字が出た回数およ
び確率を出力するプログラムを作成せよ。 とくにN=100と10000
の場合について, 確率のバラツキはどちらが小さいか確認せよ。
( ex10-7.c)
18
モンテ・カルロ法
特別課題 10-8
乱数を利用して,円周率を計算せよ. なお,下の図を参
考にせよ.
使う乱数の数は10000, 1000000, 100000000と変え,
それらの結果を比較せよ. ( ex10-8)
この部分の
面積はπ/4
[注] 0と1の間の実数の乱数を得るには
例えば
x=(double) rand()/RAND_MAX;
とするとよい.
19
ドラクエもどき3
特別課題 10-9
dq2-1.c, dq2-2.cを改造し、メタルスライムに勝ったり負け
たりするゲームを作成せよ.
20
実習結果のレポート
• 2つのソースファイル「ex10-6.c」、「ex10-7.c」を
添付ファイルにしてメールを送ってください。
• 宛先: [email protected]
• 件名:コンピューター基礎実験10
• 本文:感想および一言
21