スライドショー

【C言語入門】乱数(rand)の使い方

乱数って使ってますか?ある範囲の数値の中から偏りなく無作為に数値を選んで使いたい場合に乱数を使用します。自動で繰り返し処理を行いたい場合などに使う数値として乱数はよく使われます。

例えばパスワードなどでは乱数を使って無作為に英文字や数値を選んで並べたものが使われています。

この記事では、乱数について

  • 乱数とは
  • randの使い方
  • randを使ったサンプルコード

など基本的な内容から、具体的な使い方の内容についても解説していきます。今回は乱数について、使い方をわかりやすく解説します!

乱数とは

乱数とは一意的ではなくランダムで何が出るかわからない数字のことです。C言語ではrand関数を使ってよく疑似乱数を生成させます。

プログラミングで生成する乱数の羅列はそれぞれの値はランダムで生成されますが、同じ羅列を再現して出すことができるので何が出るか先読みすることができます。したがって本当の意味での乱数ではないので、区別して疑似乱数と呼んでいます。

randの使い方

rand関数を使って乱数を発生させる方法についてみていきましょう。

基本的な使い方

rand関数を使うためにはヘッダーファイル「stdlib.h」をインクルードする必要があります。rand関数を使うと0~RAND_MAXまでの整数の乱数を生成することができます。RAND_MAXはヘッダーファイル「stdlib.h」で定義されています。

RAND_MAXの値は環境により異なりますので注意しましょう。この解説では下記のように定義されている環境で確認しています。

#define RAND_MAX 0x7fffffff

0x7fffffffは十進数で表すと2147483647となります。

したがって0~2147483647までの乱数を発生させることになります。rand関数は引数は指定しません。

それではサンプルコードで使い方をみていきましょう。

#include <stdio.h>
#include <stdlib.h>
 
int main(void) {
    printf("RAND_MAX: %d\n", RAND_MAX);

    // 0から2147483647までの乱数を発生
    for(int i = 0; i < 3; i++) {
        printf("%d\n", rand());
    }
 
    // 1から10までの乱数を発生
    for(int i = 0; i < 3; i++) {    
        printf("%d\n", rand() % 10 + 1);
    }
    
    return 0;
}

実行結果:

RAND_MAX: 2147483647
1804289383
846930886
1681692777 
6
4
6

このサンプルコードでは3回繰り返して乱数を発生させています。乱数を発生させていますので、環境を変えて実行した結果はこの結果とは異なる表示になります。

この環境ではrand関数は0から2147483647までの乱数を生成しますので、例えば1~10までの乱数を生成したい場合は10の剰余に1加えて1~10の数値を算出します。なお、このサンプルコードでは繰り返し実行しても同じ結果が繰り返し出力表示されますので注意しましょう。実行するたびに違う結果を出力表示したい場合はrand関数を使う前に初期化を行う必要があります。

初期化の方法について詳しくみていきましょう!

初期化の方法

初期化を行うにはsrand関数を使用します。

srand関数の引数には符号なし整数を使用します。符号なし整数に同じ値を使うと乱数は同じ値で初期化されます。乱数の初期値を毎回変えたい場合は、一般にtime関数を使って現在の時刻を取得して利用します。

time関数は現在の歴時刻を秒単位で取得します。ちなみに歴時刻とはグリニッジ標準時の1970年1月1日0時から現在までの経過時間を秒単位で表したものです。time関数を使うためにはヘッダーファイル「time.h」をインクルードする必要があります。time関数の引数にNULLを指定して使用します。

それではサンプルコードで確認していきましょう。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
 
int main(void) {
    for(int i = 0; i < 3; i++) {
        srand(1); // 乱数の初期化
        printf("%d回目の乱数発生: ", i + 1);
        
        // 0から2147483647までの乱数を発生
        for(int j = 0; j < 3; j++) {
            printf("%d, ", rand());
        }
        printf("\n");
    }
    
   for(int i = 0; i < 3; i++) {
        srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化
        printf("%d回目の乱数発生: ", i + 1);
        
        // 0から2147483647までの乱数を発生
        for(int j = 0; j < 3; j++) {
            printf("%d, ", rand());
        }
        sleep(1); // time関数で取得する時刻を変えるために1秒待機
        printf("\n");
    }
    
    for(int i = 0; i < 3; i++) {
        srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化
        printf("%d回目の乱数発生: ", i + 1);
        
        // 1から10までの乱数を発生
        for(int j = 0; j < 3; j++) {
            printf("%d, ", rand() % 10 + 1);
        }
        sleep(1); // time関数で取得する時刻を変えるために1秒待機
        printf("\n");
    }
    
    return 0;
}

実行結果:

1回目の乱数発生: 1804289383, 846930886, 1681692777, 
2回目の乱数発生: 1804289383, 846930886, 1681692777, 
3回目の乱数発生: 1804289383, 846930886, 1681692777, 
1回目の乱数発生: 1004092231, 3888874, 662954966, 
2回目の乱数発生: 1779225463, 899014191, 250342318, 
3回目の乱数発生: 1467717538, 1774429879, 1966374531, 
1回目の乱数発生: 5, 8, 7, 
2回目の乱数発生: 3, 8, 7, 
3回目の乱数発生: 9, 9, 7, 

このサンプルコードでは、srand関数を使ってrand関数を初期化しています。まずsrand関数の引数に1を指定して初期化しrand関数で乱数を発生させた場合は、3回とも同じ乱数が生成されています。次にsrand関数の引数にtime関数を使って初期化しrand関数で乱数を発生させた場合は、3回とも違う値の乱数が生成されています。

なお、time関数は秒単位で歴時刻を取得しますので繰り返し処理が1秒以内で終了する場合は同じ歴時刻を取得します。

そうすると同じ値で初期化することになりますので、このサンプルコードではsleep関数を使って1秒待機させ違う歴時刻を取得するようにしています。sleep関数を使うにはヘッダーファイル「unistd.h」をインクルードする必要があります。

randを使ったサンプルコード

rand関数を使って乱数を生成するサンプルコードとして、サイコロの出目を表示する例とじゃんけんの勝ち負けを表示する例をご紹介します。

サイコロ

このサンプルコードではrand関数を使って1~6までの乱数を生成し出力表示しています。

srand関数を使って現在の歴時刻で初期化していますので、実行するたびに出力表示は変わります。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化

    for(int i = 0; i < 3; i++) {
        printf("%d回目: ", i + 1);
        
        // 1から6までの乱数を発生
        int num = rand() % 6 + 1;
        
        switch(num) {
            case 1:
                printf("一の目が出ました\n");
                break;
            case 2:
                printf("二の目が出ました\n");
                break;
            case 3:
                printf("三の目が出ました\n");
                break;
            case 4:
                printf("四の目が出ました\n");
                break;
            case 5:
                printf("五の目が出ました\n");
                break;
            case 6:
                printf("六の目が出ました\n");
                break;
            default:
                printf("numの値が不正です\n");
        }
    }
    
    return 0;
}

実行結果:

1回目: 四の目が出ました
2回目: 二の目が出ました
3回目: 三の目が出ました

じゃんけん

このサンプルコードではrand関数を使って0~2までの乱数を生成しています。0の場合はグー、1の場合はチョキ、2の場合はパーとしてじゃんけんの勝ち負けの出力表示処理をしています。

こちらもsrand関数を使って現在の歴時刻で初期化していますので、実行するたびに出力表示は変わります。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
 
int main(void) {
    srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化

    for(int i = 0; i < 3; i++) {
        printf("%d回目: ", i + 1);
        
        // 0から2までの乱数を発生
        int num1 = rand() % 3;
        int num2 = rand() % 3;
        
        if(num1 == num2) {
            if(num1 == 0) {
                printf("Aはグーで、Bもグー。引き分け。\n");
            } else if(num1 == 1) {
                printf("Aはチョキで、Bもチョキ。引き分け。\n");
            } else {
                printf("Aはパーで、Bもパー。引き分け。\n");
            }
        } else if(num1 == 0) {
            if(num2 == 1) {
                printf("Aはグーで、Bはチョキ。Aの勝ち。\n");
            } else {
                printf("Aはグーで、Bはパー。Bの勝ち。\n");
            }
        } else if(num1 == 1) {
            if(num2 == 0) {
                printf("Aはチョキで、Bはグー。Bの勝ち。\n");
            } else {
                printf("Aはチョキで、Bはパー。Aの勝ち。\n");
            }
        } else if(num1 == 2) {
            if(num2 == 0) {
                printf("Aはパーで、Bはグー。Aの勝ち。\n");
            } else {
                printf("Aはパーで、Bはチョキ。Bの勝ち。\n");
            }
        }
    }
    
    return 0;
}

実行結果:

1回目: Aはパーで、Bもパー。引き分け。
2回目: Aはグーで、Bはチョキ。Aの勝ち。
3回目: Aはグーで、Bはパー。Bの勝ち

まとめ

ここでは、乱数の生成について説明しました。

rand関数を使って乱数を生成する場合、実行するたびに同じ値の乱数を生成させるか、毎回繰り返し同じ値で初期化して同じ値の乱数を生成させるか、毎回違う値で初期化して違う値の乱数を生成させるか目的にあわせて乱数の生成方法を選ぶ必要があります。

目的にあわせて使い分けることができるように、この記事を何度も参考にして下さいね!

LINEで送る
Pocket

無料でSEからWebエンジニアへ転職しませんか?



侍エンジニア塾では、完全未経験の方から現在SEだけどプログラミングはやっていないという経験者まで、幅広い方々の人生を好転させるプログラミング指導を行ってきました。SEの方とお話していくなかで、

  • システムエンジニアという職業だけどコードが書けない
  • 事務作業が多くスキルがないため将来が不安
  • スクールに通うと完全未経験者と同じスタートになるからレベルが合わない
という、すでに知識があるSEならではのお悩みがあることに気づきました。そんな方におすすめなのが、弊社の「転職コース 」です。

弊社では、マンツーマンでレッスンを行いますので、現在お持ちの知識レベルからカリキュラムを作成いたします。さらにこちらの転職コースは無料で受講を始められて転職成功でそのまま卒業できるというとてもお得なコースとなっています。

既に知識のあるSEといっても転職は年齢が若いほど受かりやすいため、まずは無料体験レッスンで今の現状や理想の働き方について一緒に考えていきましょう。

まずは無料体験レッスンを予約する

書いた人

長野 透

長野 透

熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
お問合せはこちらでも受け付けています。
[email protected]

おすすめコンテンツ

あなたにぴったりなプログラミング学習プランを無料で診断!

プログラミング学習の効率を劇的に上げる学習メソッドを解説