C言語で乱数を得る最初の一歩は、標準ライブラリ<stdlib.h>のrand()を理解することです。
randは0からRAND_MAXまでの整数を返す擬似乱数生成器で、初心者の方はこの「範囲」と「使い方」を丁寧に押さえることが大切です。
この記事では、単発と複数回の生成、printf()での確認、環境ごとの違い、そして使う際の注意点を順序立てて解説します。
randの基本
rand()は0〜RAND_MAXの整数を返す
rand()は標準ライブラリ<stdlib.h>に含まれる関数で、呼び出すたびに0以上かつRAND_MAX以下の整数を返します。
戻り値の型はintです。
C言語標準では分布の性質には強い保証はありませんが、一般的な実装では一様分布に近い擬似乱数が生成されます。
関数プロトタイプは次のとおりです。
int rand(void);
範囲の端(0とRAND_MAX)も含まれることを覚えておくと、境界条件のテストに役立ちます。
RAND_MAXの意味
RAND_MAXはマクロ定数で、rand()が返し得る最大値を表します。
定義場所は<stdlib.h>で、少なくとも32767であることが標準で保証されています。
ただし実際の値は処理系に依存し、より大きい場合があります。
つまり「何ビットの乱数が得られるか」は環境次第です。
randの使い方
乱数を1回生成する
基本形は「必要に応じて1回rand()を呼び、intで受け取る」というものです。
実運用では毎回同じ並びを避けるため、プログラム開始時に1度だけsrand()で乱数の種(シード)を与えるのが通例です(シードの詳細は別記事で扱います)。
#include <stdio.h>
#include <stdlib.h>  // rand, srand, RAND_MAX
#include <time.h>    // time
int main(void) {
    // 実行ごとに異なる系列にするためのシード設定(詳細は別記事)
    srand((unsigned)time(NULL));
    // 0〜RAND_MAXの乱数を1回生成
    int r = rand();
    // 値を表示
    printf("生成された乱数: %d\n", r);
    return 0;
}出力例(一例):
生成された乱数: 1804289383上記の数字は実行環境により変わります。
ループで複数回生成
複数の乱数が必要なときは、シード設定は最初の1回だけにして、その後はrand()をループで呼び出します。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
    srand((unsigned)time(NULL));  // シードは1回だけ
    // 10個の乱数を生成して表示
    for (int i = 0; i < 10; ++i) {
        int r = rand();  // 0〜RAND_MAX
        printf("%2d回目: %d\n", i + 1, r);
    }
    return 0;
}出力例(一例):
 1回目: 1103527590
 2回目: 377401575
 3回目: 894259142
 4回目: 960570631
 5回目: 1804289383
 6回目: 846930886
 7回目: 1681692777
 8回目: 1714636915
 9回目: 1957747793
10回目: 424238335実行ごとに値が変化していれば、シード設定と乱数生成が適切に動いています。
printf()で値を確認
rand()の戻り値はintです。
表示には%d指定子を使うのが基本です。
余計なトラブルを避けるため、型とフォーマット指定子の組み合わせは常に一致させましょう。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    // シードは省略(注意点の節で解説)
    int r = rand();  // intで受け取る
    // %dはintに対応する指定子
    printf("rand()の値(int, %%d): %d\n", r);
    // 幅や整形も可能(右寄せで10桁)
    printf("整形表示(幅10): %10d\n", r);
    return 0;
}出力例(一例):
rand()の値(int, %d): 41
整形表示(幅10):         41改行\nを付けると、出力がバッファリングされずに見やすくなります。
RAND_MAXの確認とポイント
値は環境によって違う
RAND_MAXは処理系依存です。
以下は代表的な環境の一例です。
実際には各自の環境で確認してください。
| 環境の例 | RAND_MAXの値 | 備考 | 
|---|---|---|
| Windows(MSVC) | 32767 | 15ビット相当 | 
| Linux(glibc) | 2147483647 | 31ビット相当 | 
| macOS(Clang, libSystem) | 2147483647 | 31ビット相当 | 
| MinGW(MSVCRT系) | 32767 | 15ビット相当 | 
この違いにより、得られる乱数の「粗さ」や上限が環境で変わります。
0と最大値も出る
rand()の範囲は0以上かつRAND_MAX以下で「両端を含む」ため、理屈の上では0もRAND_MAXも出現し得ます。
いずれも確率は約1 / (RAND_MAX + 1)です。
境界値を前提にしたテストではこの点を意識しておくと安全です。
実行してRAND_MAXを表示
自分の環境のRAND_MAXを知るには、実際に表示させるのが確実です。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
    printf("この環境のRAND_MAX: %d\n", RAND_MAX);
    srand((unsigned)time(NULL));   // 実行ごとに系列を変える
    printf("サンプル乱数(1): %d\n", rand());
    printf("サンプル乱数(2): %d\n", rand());
    return 0;
}出力例(一例):
この環境のRAND_MAX: 2147483647
サンプル乱数(1): 1609348863
サンプル乱数(2): 1481765933数値は環境により異なるので、同じ結果にならなくても問題ありません。
randの注意点
シード未設定は毎回同じ結果
シード(srand())を設定しないと、実行のたびに同じ並びの値が得られます。
テストには便利ですが、実運用での乱数らしさは失われます。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    // srand(...) を呼ばない例
    for (int i = 0; i < 5; ++i) {
        printf("%d ", rand());
    }
    printf("\n");
    return 0;
}出力例(1回目):
41 18467 6334 26500 19169出力例(2回目):
41 18467 6334 26500 191692回とも同じ並びになっていることが分かります。
実行ごとに変えたい場合は、プログラム開始時にsrand((unsigned)time(NULL))などでシードを与えましょう(理由や選び方は別記事で解説します)。
int型の値として扱う
rand()の戻り値はintです。
代入や表示ではintを前提に扱います。
- 代入例: int r = rand();
- 表示例: printf("%d\n", r);
フォーマット指定子を間違えると未定義動作の原因になります。
特に%ldや%uなど他型の指定子を流用しないように注意してください。
なおrand()は暗号用途には不適です。
セキュアな乱数が必要な場合は別のAPIを検討します。
範囲の変更は別記事で解説
0〜RAND_MAXのままでは使いにくい場面も多く、例えば1〜100などの範囲に変換したくなります。
よくある書き方はrand() % 100 + 1ですが、分母(RAND_MAX + 1)が範囲で割り切れないと偏りが生じる可能性があります。
正しい範囲変換の方法や偏りの話題は別記事で丁寧に解説します。
本記事では「まずは0〜RAND_MAXの整数を安全に受け取り、理解する」ことに集中しましょう。
まとめ
rand()は0〜RAND_MAXの整数を返す基本の乱数生成関数で、RAND_MAXは処理系依存の上限値です。
初心者の方は、(1) <stdlib.h>をインクルードし、(2) 必要ならsrand()でシードを1度だけ設定し、(3) intで受けて%dで表示する、という手順を確実に身につけてください。
境界値(0と最大値)も出得ること、RAND_MAXが環境で異なることを確認し、用途に応じて正しい範囲変換やシードの扱いへと理解を広げていきましょう。

 
			