(3.1.1) if ... else を使った自明なプログラム。
#include <stdio.h> main() { int x; printf("数を入れてください.\n"); scanf("%d", &x); /* 数の入力 */ if (x == 0) { printf("その数は零です.\n"); } else if (x > 0) { printf("その数は正です.\n"); } else { printf("その数は負です.\n"); } }
(3.1.2) if の行以降については次を見よ。
if (条件1) { 文1 } else if (条件2) { 文2 } else if (条件3) { 文3 } else { 文4 } |
|
else if は何個あってもかまわない。
(3.1.3) if が一つしかなく,かつ,else がないとき。
if (条件1) { 文1 } |
|
(3.1.4) K&R2 では §3.2, §3.3 を参照。 そこでは省略可能な中カッコを省略しているが, 私のやり方のように全てつけておくほうが間違いが少ない。 インデントについても上の例でしっかり覚えよ。 中カッコの中の文はタブ一つ分だけ余計に字下げするのだった。 くわしくは §2.5 を見よ。
(3.1.5) if (...) の中で使える記号は、数学上の記号と少々異なる。 (for の継続条件で使える記号もまったく同じ。)
|
注意:
「=<」「=>」は不可。
「if (x = 0)」, 「0 < x < 8」は別の意味。 |
(3.1.6) 「if (a+b < c+d)」のように if の小カッコ内で計算をしてから比較することもできる。
(3.1.7) K&R2 では §2.6, §A7.9, §A7.10 を参照のこと。
(3.1.8) 「かつ」は if (x > 0 && x < 8), 「または」は if (x < 0 || x > 2) { と書く。 「&」はシフトしながら 6のキーを、 「|」はシフトしながら ¥のキーを打つ。 K&R2 では §2.6 を見よ。 「かつ」も「または」も同じ文字を二つ打つことに注意。 「&」「|」をひとつだけ書くと,別の意味になる。
(3.1.9) (3.1.1) のプログラムで、 if (x = 0) と書いたらどうなるか。 0 をほかの数に変えての実験もしてみよ。
(3.1.10) アラレ数とは,次の漸化式で決まる数列である。 「ある項が偶数のときは次の項はその 1/2, 奇数の時はその項の 3 倍 + 1」。 どんな数から始めても 4, 2, 1, 4, 2, 1 ... の無限ループに陥ると予想されている。 このプログラムは,1 になったらそこで終わる。
/* アラレ数 */ #include <stdio.h> main() { int n; printf("自然数を入れてください.\n"); scanf("%d", &n); /* キーボードから数を入力 */ for ( ; n != 1; ) { if (n % 2 == 0) { /* n が偶数のとき */ n = n / 2; } else { /* n が奇数のとき */ n = 3 * n + 1; } printf("%d ", n); } printf("\n"); }
(3.1.11) 二重の for と if ... else を組み合わせたプログラム。
/* 2 から 99 までの整数の最小の素因数を出力 */ #include <stdio.h> main() { int n, p; for (n = 2; n < 100; n++) { for (p = 2; n % p != 0; p++) { ; /* 空文。なにもしない */ } if (n == p) { printf("%d は素数です.\n", n); } else { printf("%d の最小の素因数は %d です.\n", n, p); } } }
(3.1.12) 練習問題:上のプログラムを,素数のみを出力するよう改変してみよ。 素数を単に並べて出力すればよい。 2 3 5 7 11 13 ... のように。
(3.2.1) 変数名には,a, b, x, y のような一文字はもちろん,sum, total のように二文字以上からなる文字列も使える。 英語の単語でなくてももちろん可。 x11 のように数字がはいっても構わないが, 数字で始まる 1x などは不可。 (使おうとしたらどうなるか?)
(3.2.2) x1, x2, x3 とあったら人間は関連のある変数だろうと想像するが, コンパイラにとっては全く無関係な,ただの三つの変数である。
(3.2.3) 配列を使った自明なプログラム。
#include <stdio.h> int a[10]; /* 配列の宣言。これで a[0], ..., a[9] が使える */ main() { int i; for (i = 0; i < 10; i++) { /* 配列の要素に代入 */ a[i] = i * i; } for (i = 0; i < 10; i++) { /* 配列の要素を印字(=出力) */ printf("a[%d] は %d です.\n", i, a[i]); } }
(3.2.4) 「配列」とは, 0 からある自然数までの整数で添え字づけられた有限個の変数 x[0], x[1], x[2], ..., x[N-1] を一斉に定義し,一括して扱うものである。 K&R2 では §1.6 を参照。
(3.2.5) 「配列の宣言。...」の行。こう書くと, a[0] から始まる 10 個の int 型変数が使える。 すなわち,a[0], a[1], a[2], ..., a[9] が使える。 a[10] は使えない。うっかり使わないよう,注意。
(3.2.6) 「配列の宣言は main() の中カッコの外で行ない, ほかの変数の宣言は main() の中カッコの中で行なう」 という規則があるわけではないが, ある事情により,この授業ではそうする。 正確なところは K&R2 §1.10, §4.3 参照。
(3.2.7) 同じ定数が何度も現れる場合,#define を利用すると便利である。 #define の次に書かれた文字列は,その右に書かれたもので置き換えられる。 次の例は (3.2.3) のプログラムとまったく同一である。 配列の大きさを変えたくなった場合, #define N の右の数を変えるだけで, 複数回あらわれる N の値を一気に変えることができる。
#include <stdio.h> #define N 10 int a[N]; /* 配列の宣言。これで a[0], ..., a[N-1] が使える */ main() { int i; for (i = 0; i < N; i++) { /* 配列の要素に代入 */ a[i] = i * i; } for (i = 0; i < N; i++) { /* 配列の要素を印字(=出力) */ printf("a[%d] は %d です.\n", i, a[i]); } }
(3.2.8) 練習問題:上のプログラムを改変し, a[i] に i*i を代入したあと, 隣あった項どうしの差 (a[1] - a[0], a[2] - a[1], ..., a[N-1] - a[N-2]) を出力するプログラムを書け。 出力時に,添え字が範囲外の値にならないよう注意せよ。 次に,わざと間違えて,添え字が範囲外の値になるようにせよ。 それをコンパイル・実行してみよ。
(3.3.1) 「乱数」が数学でどう定義されるかは,ここでは考えない。 計算機でいう乱数とは, 種(たね)と呼ばれる整数を元に漸化式を使って発生させる, 乱数のように見える数列のことである。
(3.3.2) 関数 rand() は,小カッコの中には何も書かずに呼び出す。 呼び出されるたびに, 0 以上 RAND_MAX 以下の整数(int 型)に値をとる乱数の項を, 一つずつ返す。次のプログラムでは,一行に一つずつ,全部で 10 個の整数が出力される。 その並びが乱数,というわけである。
#include <stdio.h> #include <stdlib.h> /* rand() */ main() { int i; for (i = 0; i < 10; i++) { /* 10 項からなる乱数列を発生 */ printf("%d\n", rand()); } }
(3.3.3) 2行目。関数 rand() を使うには stdlib.h を #include することが必要である。 どの関数を使う際にどの .h ファイルが必要になるのかは, この授業ではそのつど教える。また,K&R2 の付録に書いてある。 「/* rand() */」は, 「rand() を使うためにこの行を書いた」という覚え書きである。
(3.3.4) RAND_MAX はコンパイラごとに違う値を取り得る定数なので, 次のプログラムで調べよ。
#include <stdio.h> #include <stdlib.h> /* RAND_MAX */ main() { printf("%d\n", RAND_MAX); }
興味のある人は値をメモしておこう。
(3.3.5) (3.3.1) のプログラムは,毎回同じ乱数列を出力する。 それでは困るので,現在時刻を乱数の種(たね)にすることを考える。
#include <stdio.h> #include <stdlib.h> /* rand(), srand() */ #include <time.h> /* time() */ main() { int i; { /* この中カッコの中(乱数の種の設定)はわからなくてもよい */ unsigned seed = (unsigned)time(NULL); /* 現在時刻を取得して */ printf("乱数の種は %u です.\n", seed); /* その値を出力 */ srand(seed); /* それを乱数の種に */ } for (i = 0; i < 10; i++) { printf("%d\n", rand()); } }
センターの Linux でこのプログラムを動かすと, 秒未満は無視されるようである。(二人で“同時に”実行してみよ。)
(3.3.6) rand() % 100 とすると, 0 以上 100 未満の整数に値をとる乱数が得られる。 厳密に言えば,RAND_MAX の値によっては, 0 の出現率と 99 の出現率はわずかながら異なるが, この授業ではそこまでは気にしないことにしよう。
(3.3.7) 練習問題その1:(3.3.5) のプログラムを,(3.3.6) のように改造し, 0 以上 100 未満の整数に値をとる乱数が得られること, および,実行するごとにその乱数列が異なることを確認せよ。
(3.3.8) 練習問題その2:(3.3.5) のプログラムを, 1 以上 100 未満の整数に値をとる乱数が発生されるよう改変せよ。