「まず覚えるCの文法」
(校正中)
P45: 再帰
//-------------------------------------
#include <stdio.h>
int gcd(int i, int j){
int k;
if(i<0 || j<0){return 0;}
if(j<i){k=j; i=j; j=k;}
k=j%i;
if(k>0){
printf("%d%%%d==%d\n", j, i, k);
return gcd(k, i);
}else{return i;}
}
int main(void){
printf("i==%d\n", gcd(18, 30));
return 0;
}
//-------------------------------------
P46: 静的な局所変数
//-------------------------------------
#include <stdio.h>
int noise(int k){
static int n=1;
if(k!=0){n=k;}else{n=(5*n+1)%8;}
return n;
}
int main(void){
int i;
for(i=0; i<8; i++){
printf("%d ,", noise(0));
}
return 0;
}
//-------------------------------------
P47: マクロ
//-------------------------------------
#include <stdio.h>
#define N 2
double av(int *p){
double x=0; int i;
for(i=0; i<N; i++){x=x+p[i];}
return x/N;
}
int main(void){
int v[N], i;
for(i=0; i<N; i++){
printf("v[%d]=");
scanf("%d", &v[i]);
}
printf("average=%f\n", av(v));
return 0;
}
//-------------------------------------
|
P45 の gcd() はユークリッドの互除法で i と j の
最大公約数を求める関数です.
・ユークリッドの互除法の原理については Wikipedia
等で調べてください.
・18,30 が代入された i,k は gcd() 内では通常の
変数と同様に扱われます(#42).
・gcd(18, 30) の実行中に gcd(12, 18) が呼び出され
18%12!=0 なので gcd(6, 12) が呼び出されます.
このように関数が自分を呼び出すことを再帰呼び出し
といいます.
・gcd(12, 18) を実行するとき実引数を記憶する領域が
新しく準備されるので,gcd(18, 30) 計算時の i,k
の値は保存されます(#43).
・gcd(6, 12) では 12%6==0 なので「return i;」の方が
選択され,再帰呼び出しが終了します.
・再帰呼び出しを使うとアルゴリズムが分かり易くなり
ますが実行時間とメモリを贅沢に使います.階乗を
int fact(int n){
if(n>1){
return n*fact(n-1);
}else{return 1;}
}
で計算するような無駄は止めましょう.
関数内で宣言された変数(局所変数)の値は通常関数の
実行が終了すると使えなくなりますが,P46 の n のよう
に宣言すれば使えるようになります.P46 の noise() は
0 から 7 までの値をランダムに選択したように見せかけ
て戻り値とする関数です.
・線形合同法による擬似乱数の生成についてはWikipedia
等で調べてください.
・擬似乱数の数列は noise(0) で生成します.初期値を
設定したいときは noise(k) を使います.
・静的な変数はコンパイル時に領域が確保され,初期値が
指定されていれば,機械語プログラムにその値が設定さ
れます.これに対して,自動変数は関数が呼び出される
たびにスタック上に領域が与えられ(初期値の指定があ
れば)毎回初期化されます.
・局所変数を静的にすれば,関数外からの書き換えを防ぎ
つつ値を保持することができます.
Cの処理系ではソースプログラムをプリプロセッサで変更
してからコンパイルします.「#」で始まる行はプリプロ
セッサに対する指令で,これまで説明しなかった
#include <stdio.h>
は「この行を stdio.h というファイルで置換しなさい」と
いう指令です(#60).P47 のプログラムの
#define N 2
は,マクロ N の定義で,プリプロセッサはソースプログラ
ムのこの行以降のすべての N を 2 で置換します.
・小さな N の値でプログラムをデバッグし,使うときは
N の大きな値にしてコンパイルしなおすのが便利です.
・[#47] に示されているような引数付きのマクロも定義
できますが,実行時間に厳しい制約がなければ引数付き
マクロは使わない方が無難です.
|