/* calculate_sum * * (C) J. Makino Version 1.0 Jan 26, 1997 */ #include <stdio.h> int n ; int data[100]; int i,sum; void main() { printf("How many numbers you want to input?"); scanf("%d",&n); for (i=0;i<n;i++) scanf("%d",&data[i]); sum = 0; for (i=0;i<n;i++){ sum += data[i]; printf("data[%2d]=%5d, sum = %d\n", i,data[i], sum); } }このプログラムでは、配列というものを使う。
int data[100] ;と変数宣言のところに書くと、100個の整数型変数ができ、それぞれが data[0] から data[99] までといった風に、番号で指定して操作 できる。この番号のことを、「専門用語」で「添字」(index)という。
配列の便利なところは、まず、変数宣言で int data0,data1,data2, .... data99 と書くよりずっと短くて済む(100万個変数が欲しかったら 大きな違いである)ということ、それから実行部も簡潔な繰り返しで書けると いうことである。特に大事なのは、番号(添字)に変数が使えるということで ある。このことのために、上のように、ループの中で配列の要素を順番に見る とか値をいれるとかいったことができる。
How many numbers you want to input?5 1 2 3 4 5 data[ 0]= 1, sum = 1 data[ 1]= 2, sum = 3 data[ 2]= 3, sum = 6 data[ 3]= 4, sum = 10 data[ 4]= 5, sum = 15
/* sort_data_from_file * * (C) J. Makino Version 1.0 Jan 26, 1997 */ #include <stdio.h> int n; double data[100]; int i,j; double work; void main() { for (i=0;scanf("%lf",&data[i])==1;i++); n =i; printf("Input data\n"); for (i=0;i<n;i++) printf(" %5.2f",data[i]); printf("\n"); for (i=0;i<n-1;i++){ for (j=i+1;j<n;j++){ if (data[i] > data[j]){ work = data[i]; data[i] = data[j]; data[j]= work; } } } printf("Sorted data\n"); for (i=0;i<n;i++) printf(" %5.2f",data[i]); printf("\n"); }このプログラムは、入力した数を小さい順に並べ変えて出力する。並べ変える 原理は、以下のようなものである。
simple_sort < sample.datとシェルウインドウで入力すれば結果が得られるはずである。
注意 コンパイルして作るプログラムの名前には sort は使わな いこと。これは、この名前の別のプログラムがあらかじめ準備されていて、そ ちらが実行されてしまうからである。
なお、
for (i=0;scanf("%lf",&data[i])==1;i++);という繰り返しは「実行部」が";"だけで何もない。これは、 scanf という関 数が「データがうまく読めればその読んだデータの数を返す」関数であるとい うことを利用した、 C 言語では良く使う書き方である。既にやったように、 for は
for ([0]初期化文; [1]条件; [3]文){[2]実行文 ; ...}という形をしていて、0-1-2-3-1-2-3... の順に繰り返し実行される。ここで、「条件」のところに関数が入った式があれば、その関数が実行されて、返ってきた値が使われる。
time simple_sort < sample.datという風に入力すると、実行結果のあとにもう一行
0.040u 0.080s 0:00.56 21.4% 0+135k 2+0io 21pf+0wというような出力が出てくる。この最初の数字が秒単位の実行時間である。な お、実際にかかった時間はもっと長いことがあり得る。これは、ファイルの読 み書きの時間は正確には入らないこと、また何人かで1台の計算機を使ってい るのでその分余計に時間がかかることによる。
/* factrial * * (C) J. Makino Version 1.0 Jan 26, 1997 */ #include <stdio.h> double factrial(double n) { if (n <=1.0){ return 1.0; }else{ return n*factrial(n-1); } } void main() { double n; printf("Enter n : "); scanf("%lf",&n); printf("N = %5.0f N! = %20.13g\n", n,factrial(n) ); }上の例 は、階乗を計算するプログラムである。階乗は、下のように定義される:
CやPascalのような「近代的」プログラミング言語では、この定義に従って素直にプログ
ラムを書くことができる(これに対して、古いBASICなどではできない)。上の例では、まさに、
再帰を使うことで、角度、長さを変えて自分自身を呼び出すという形で簡潔に
アルゴリズムが表現できている。
なお、このプログラムを打ち込んで、そのままコンパイルしようとしてもうま
くできない。これは、三角関数(sin, cos) がどこにあるか指定されてい
ないからである。これは以下のように, -lXtc -lX11 にさらに追加して指定する。
factrial(5)
→5*factrial(4)
→5*(4*factrial(3))
→5*(4*(3*factrial(2)))
→5*(4*(3*(2*factrial(1))))
→5*(4*(3*(2*1)))
→5*(4*(3*2))
→5*(4*6)
→5*24
→120
練習
お絵書き
再帰を使って複雑な図形を書いてみよう。
/* tree
*
* (C) J. Makino Version 1.0 Jan 26, 1997
*/
#include <stdio.h>
#include <math.h>
#include </home/makino/text/xgraph.h>
#define PI 3.14159265358979
int gdriver, gmode;
double x,y,vx,vy;
void tree(int n, int x, int y, double angle, double length)
{
int x1, y1;
if (n > 0){
setcolor( n % 7 + 1);
x1 = x + length*cos(angle);
y1 = y - length*sin(angle);
line(x,y,x1,y1);
tree(n-1,x1,y1,angle + 0.25, length*0.7);
tree(n-1,x1,y1,angle - 0.25, length*0.7);
}
}
void main()
{
char dumstr[100];
initgraph(gdriver, gmode, "");
cleardevice();
tree(10, getmaxx()/2, getmaxy(), PI/2, getmaxy()/ 4);
gets(dumstr);
gets(dumstr);
closegraph();
}
これは、樹形図を書くプログラムである。原理は、指定した長さと角度で一本
線を引き、その先から角度をつけて2本線を引き、それぞれの端からまた角度
をつけて、、、というのを繰り返すだけである。
gcc tree.c -o tree -lXtc -lX11 -lm
練習
(ヒント:drand48() という関数を呼ぶと、0 から x まで
の範囲の乱数 --- デタラメな数 --- を返す。これを使って枝分かれの長さ、
角度を変えて見よう)
レポート
前回と今回の「練習」の中から、2つ以上を選んで解き、
をまとめて提出すること。ただし、前回の2番は、それだけでは1問と認めな
い。なお、提出は、メイルで
makino-1@chianti.c.u-tokyo.ac.jp
あてに、 Subject を kadai-3 として提出すること。グラフィックスの出力結
果は、以下のようにして提出すること。
なお、今回のレポートは適当な時期に WWW 上で公開するので、公開さ
れても構わないような内容にして下さい。締切は試験日の前日ということにします。
次回予告
次回は、全体のまとめとする。内容は未定。