おさえておきたいプログラミングの基本
ここからはいよいよC言語の応用編です。
C言語には数値ならびに数学を扱うために必要な処理が多数存在します。実用的なプログラムを作る上でこれらは欠かせません。そこで応用編の第一歩として数値・数学に関する処理および関数、更には注意点などについて説明していきます。
乱数とはでたらめな数のことです。ゲームなどでさいころを振ったり、カードをシャッフルするなどといった処理を行うには乱数の処理が欠かせません。ここでは、C言語で乱数を扱う方法を紹介していきます。
listex1-1:main.c#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc,char** argv){
int a,b;
// 乱数の初期化
srand((unsigned) time(NULL));
// 1から10までの乱数を発生させる
a = rand() % 10 + 1;
b = rand() % 10 + 1;
// 計算結果を出力
printf("%d + %d = %d\n",a,b,a+b);
return 0;
}
実行結果(実行する度に変化する)
このプログラムの特徴は、実行するたびに結果が変わることです。それは10行目、11行目で変数a,bに値を代入する際に使用するrand()関数に理由があります。まずは、このプログラムで用いられている関数を紹介しましょう。(表1-1)
表1-1.乱数に関する関数関数 | 書式 | 意味 | 使用例 |
---|---|---|---|
srand() | srand(unsigned seed); | randで発生させる乱数の系列を変更。 | srand((unsigned) time(NULL)); |
rand() | rand() | 0~RAND_MAX の間の疑似乱数を返す。 (RAND_MAXは処理系依存) | rand() % 10 + 1; |
これだけを見るとsrand()を使用する意味がよくわからないと思います。実はC言語で発生させる乱数は擬似的なもので、この処理を行わないと何度も同じパターンの乱数が発生してしまいます。
そこで、srand()関数を用いて変数を初期化するのですが、この時引数が同じでは、やはり同じパターンの数値しか出ません。そこで引数として、秒単位で現在時刻を返すtime()関数を用い、実行するごとに違う系列の乱数が出現するようにしているわけです。
表1-2.time関数関数 | 書式 | 意味 | 使用例 |
---|---|---|---|
time() | time_t time(time_t *timer); | 1970年1月1日の00:00:00 から現在までの 経過時間を秒単位で取得する。 | time(NULL); |
なお、rand()関数、srand()関数を利用するにはstdlib.hを、time()関数を利用するには、time.hをインクルードする必要があります。
では、プログラムの中身を紹介していきましょう。まず、8行目で乱数を初期化しています。次に、10,11行目で乱数を発生させていますが、 通常、rand()関数は、0からRAND_MAXという非常に大きな値を発生させます。そのため、1から10の乱数を発生させるにはまず%10をします。
これは10で割った余りという意味なので、乱数は0から9の範囲に限定されますから、それに1を足せば、1から10の値を得ることが出来るのです。(図1-1)
図1-1.1から10までの乱数を発生させる原理考え方としては難しいですが、以下の方法を覚えておくと、非常に便利でしょう。
1からnまでの乱数をえる方法C言語には、沢山の数値計算用の関数が用意されています。それらは非常にたくさんあり、全てをここで紹介することはできませんが、比較的使用頻度の高いものをここでいくつか紹介していきましょう。
まずは、三角関数を使ったサンプルを見てみましょう。
listex1-2:main.c#include <stdio.h>
#include <math.h>
#define PI 3.14
int main(int argc,char** argv){
int angle;
double rad;
printf("角度を入力してください(0~360):");
scanf("%d",&angle);
// 角度をラジアンに変換
rad = PI * (double)angle / 180.0;
// 三角関数での計算
printf("sin(%d)=%f\n",angle,sin(rad));
printf("cos(%d)=%f\n",angle,cos(rad));
printf("tan(%d)=%f\n",angle,tan(rad));
return 0;
}
実行結果(キーボードから角度を入力しEnterキーを押す)
sin、cos、tanは、その綴りのとおり、ずばりサイン・コサイン・タンジェントを意味します。つまり、数学でいうところの三角関数です。なお、これらはすべて、math.hに含まれています。(表1-3.参照)
表1-3.三角関数関数 | 書式 | 意味 | 使用例 |
---|---|---|---|
tan() | tan(double rad); | ()に指定したラジアンを入れるとタンジェントが得られる。 | doube a = tan(2*3.14); |
sin() | sin(double rad); | ()に指定したラジアンを入れるとサインが得られる。 | doube a = sin(2*3.14); |
cos() | cos(double rad); | ()に指定したラジアンを入れるとコサインが得られる。 | doube a = cos(2*3.14); |
C言語の三角関数の引数として与えるのは角度ではなくラジアンだという点に注意してください。通常、角度を0度から360度までで測るやり方を、度数法(どすうほう)と言いますが、これに対し、ラジアンで角度を指定する方法を弧度法(こどほう)と言います。
ラジアンという考え方は180度をπ(パイ)ラジアンと考えるやり方で、一般の角度をラジアンに変換するには180で割りそこに円周率をかけてやる必要があります。
この計算は、12行目で行っていますが、円周率を表すPIが定義されているのは4行目です。#defineマクロはすでにファイル分割で扱いましたが、このように、定数を定義するのにも用いることが出来ます。
#defineマクロによる定数の定義このようにすれば、PIという文字列が出てくれば、このソースの中では、3.14として扱うことが出来ます。
マクロには、定数を表現する方法のほかに、引数を与えて関数のような処理を行う引数付きマクロと呼ばれるものがあります。詳しくは、こちらをご覧ください。
続いては、その他よく使う数学関数を見てみましょう。
listex1-3:main.c#include <stdio.h>
#include <math.h>
int main(int argc, char** argv) {
int n = -2;
double d1 = -2.5, d2 = 4.0;
printf("%dの絶対値は%d\n", n, abs(n));
printf("%fの絶対値は%f\n", d1, fabs(d1));
printf("%fの2乗は%fです。\n", d2, pow(d2, 2));
printf("%fの平方根は%fです。\n", d2, sqrt(d2));
return 0;
}
実行結果
使用した関数の説明をしましょう(表1-4)。
表1-4.よく使う数学関数関数 | 書式 | 意味 | 使用例 |
---|---|---|---|
abs() | abs(int n); | 与えられた整数の絶対値を求める。 | int n = abs(-10); |
fabs() | fabs(double d); | 与えられた実数の絶対値を求める。 | double d = fabs(-3.1); |
pow() | pow(double x,double y); | xのy乗を求める。 | double d = pow(3.0,2.0); |
sqrt() | sqrt(double d); | 与えらられた実数の平方根を求める。 | double d = sqrt(25.0); |
絶対値を求める関数には、abs(),fabs()の二種類があります。状況に応じて使い分けましょう。
今まで数値の演算ばかり扱ってきましたが、ビット演算も大事な演算です。以下にC言語におけるビット演算のサンプルを取り上げてみました。実行してみてください。
listex1-4:main.c#include <stdio.h>
int main(int argc, char** argv) {
// 16進数
unsigned char i = 0xf; // 2進数:00001111
unsigned char j = 0xff; // 2進数:11111111
printf("%x << 1 = %x\n", i, i << 1); // 1ビット左シフト: 2進数:00011110 = 0x1e0
printf("%x >> 1 = %x\n", i, i >> 1); // 1ビット右シフト: 2進数:00000111 = 0x7
printf("%x | %x = %x\n", i, j, i | j); // OR演算 : 2進数:11111111 = 0xff
printf("%x & %x = %x\n", i, j, i & j); // AND演算 : 2進数:00001111 = 0xf
printf("~%x = %x\n", i, (unsigned char)~i); // NOT演算 : 2進数:11110000 = 0xf0
return 0;
}
実行結果
以下、演算子とその処理の内容を表にまとめます(表1-5)。これらの演算は、いわゆる数学的な処理とは違いますが、様々な場面で応用されることがあります。基本的な使い方をおさえておきましょう。
表1-5.ビット演算に用いる演算子演算子 | 意味 | 使用例 |
---|---|---|
<< | 左シフト。指定されたビット数分、数値を左シフトする。 | 00001111 << 1 → 00011110 |
>> | 右シフト。指定されたビット数分、数値を右シフトする。 | 00001111 >> 1 → 00000111 |
| | 論理和(OR演算)。二つの数値の論理和をとる。 | 00001111 | 11111111 → 11111111 |
& | 論理積(AND演算)。二つの数値の論理積をとる。 | 00001111 & 11111111 → 00001111 |
~ | 否定演算(NOT演算)。入力された1なら0に、0なら1に反転。 | ~00001111 → 11110000 |
練習問題 : 問題1.
一週間でわかるC言語・C++言語がオンライン講座になりました!動画と音声によってさらにわかりやすくなりました!! 1講座で2つの言語を学ぶことができる上に、練習問題の回答もダウンロードできます。
Read →本講座が「1週間でC言語の基礎が学べる本」として書籍化されました!サイトの内容プラスアルファでより学習しやすくなっています!Impressより発売中です!!
Read →