隨機以及時間相關函數——C語言描述


隨機相關的函數

  頭文件 stdlib.h

  相關函數 :rand 、srand

  rand( rand C++ Reference )

  函數聲明:int rand( void );

  rand函數返回一個位於 0 - RAND_MAX之間的偽隨機整數。其中RAND_MAX在頭文件 stdlib.h 中定義( 一般為int類型可表示的最大正整數 )。

  rand函數通過一個特定的隨機數生成算法生成偽隨機數序列,該算法依據一個初始的種子值進行偽隨機數生成。偽隨機數生成可以看做一個特殊的處理過程,對於同一個輸入(種子),輸出的偽隨機值序列總是相同的( 相對於一次程序運行 )。可使用函數 srand 設置偽隨機數算法的種子,rand函數默認的種子值為1。

 

  srand( srand C++ Reference )

  函數聲明: void srand( unsigned int seed);

  初始化偽隨機序列生成器的種子值。srand函數將偽隨機數生成算法的種子使用參數 seed 初始化,使得偽隨機數生成依賴於不同的種子,避免重復。通過將種子值 seed 設置為不同的可區分的值(如程序運行時的時間),可以保證生成的偽隨機序列較為隨機。

  seed = 1時,即為偽隨機序列生成算法的默認初始初始值。

  示例:

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

#define num_of_loop 8                   /*循環次數*/   
void generate_random_num(void);         /*產生隨機序列並輸出*/

int main(void)
{
    generate_random_num();              /*使用默認的隨機種子,即 1*/

    srand( 5 );                         /*使用 5 初始化隨機種子*/
    generate_random_num();

    srand( 1 );                         /*使用 1 初始化隨機種子*/
    generate_random_num();

    return 0;
}

void generate_random_num(void)
{
    int i;
    for( i = 0 ; i < num_of_loop ; i++)
     printf("%d\t",rand());

    printf("\n");
}                                                
rand示例

  結果如下圖:

  

   可以看到默認種子的隨機序列和種子值為1的隨機序列是一樣的,而種子值為5的隨機序列則不相同。事實上,對於同一個種子值,每次程序運行產生的隨機序列都是一樣的( 注意不是每次 rand 函數調用,而是每次程序運行 )。即下一次運行上述示例時,仍產生一樣的偽隨機序列。

  為了使得由固定種子值產生的固定偽隨機序列是較為隨機的,可以在每次運行程序或調用 rand 函數之前使用不同的種子值來進行初始化。常用的方法是使用在函數調用之時的時間來作為種子值。

 

時間相關的函數

  頭文件:time.h

  相關函數:time、clock

  time( time C++ Reference )

  函數聲明:time_t time( time_t *timer );

  time函數的參數可以為空,即 0 / NULL ,此時 time 函數返回一個 time_t 類型的日歷時間;

  time函數接受一個指向 time_t 類型變量的指針作為參數,函數返回一個 time_t 類型的日歷時間,並將參數指針指向的變量值設置為該日歷時間。

  time函數返回的日歷時間精確到秒級。

  根據上文對隨機函數的描述,我們可以使用下面的語句來對隨機數序列的種子初始化,這樣每次進行初始化時的種子在秒級別的精度上是不一樣,故而可以做到較好的隨機。

 srand( (int) time(NULL) )     //使用 time 函數返回的日歷時間初始化函數,在秒級進度上保證每次種子值一致

 

  clock( clock C++ Reference )

  函數聲明:clock_t clock( void );

  clock函數返回程序運行至clock函數處所消耗的處理器時間( 時間片數 ),若調用失敗則返回 -1。

  clock函數返回值為運行消耗的時間片數,一個時間片為系統設置的一個常量時間單元,不同的系統時間片長度可能不同。可以通過在程序運行的不同位置設置兩個clock函數,並根據其差值獲得程序運行所消耗的時間片數。在頭文件 time.h 中,存在宏定義 CLOCKS_PER_SEC,定義每秒所包含的時間片數。使用時可以通過 clock 函數得到消耗的時間片數,再通過除法獲得具體消耗的秒數。

  

  其他函數:

  gmtime

  函數聲明:struct tm* gmtime( const time_t  timer );

  將time_t 類型的值轉換為UTC時間,並存放在一個 tm 類型的結構體中。

  

  localtime

  函數聲明:struct tm* localtime( const time_t timer );

  將time_t類型的值轉換為本地時間,並存放在一個 tm 類型的結構體中。

  

  actime

  函數聲明:char * actime( const tm *timer);

  將 tm 結構體的數據轉換為一個格式固定的字符串。

  

  結構體 tm ( 摘自頭文件time.h )

struct tm
{
    int    tm_sec;     /* Seconds: 0-59 (K&R says 0-61?) */
    int    tm_min;     /* Minutes: 0-59 */
    int    tm_hour;    /* Hours since midnight: 0-23 */
    int    tm_mday;    /* Day of the month: 1-31 */
    int    tm_mon;     /* Months *since* january: 0-11 */
    int    tm_year;    /* Years since 1900 */
    int    tm_wday;    /* Days since Sunday (0-6) */
    int    tm_yday;    /* Days since Jan. 1: 0-365 */
    int    tm_isdst;   /* +1 Daylight Savings Time, 0 No DST,
                     /* -1 don't know */
};

  可以看到,tm結構體記錄了年 月 日 時 分 秒 等信息,可通過 asctime 函數轉換為方便顯示的字符串形式。

  示例: 

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

int main(void)
{
    char *local_time = NULL ;
    char *UTC_time = NULL ;
    struct tm *t_in_tm = NULL ;


    time_t t = time( NULL );
    t_in_tm = localtime( &t );          //將time_t類型的數值參數轉換為tm結構體中保存(本地時間)
    local_time = asctime( t_in_tm );    //將tm類型結構體中的數值轉換為字符串形式
    printf("local time is %s\n",local_time);

    t_in_tm = gmtime( &t );             //將time_t類型的數值參數轉換為tm結構體中保存(UTC時間)
    UTC_time = asctime( t_in_tm );      //將tm類型結構體中的數值轉換為字符串形式

    printf("UTC time is %s\n",UTC_time);

    return 0;
}

  可以看到本地時間與UTC時間相差八個小時

  

  注意:可以從示例代碼中看到,在程序運行過程中,並沒有聲明一個具體的 tm 類型的結構體和存放字符串的數組用於存放數據,而只是聲明了用於指向這些結構的指針用於存放返回值。這是由於上述函數的操作是針對一個公用的靜態緩沖區來進行的,返回的參數為指向該緩沖區內具體結構的指針,故而不需要使用者另行聲明。

  在頭文件time.h中有如下警告:

  

  也就是說上述靜態緩沖區是由函數共享的,可能被其他函數覆蓋數據,使用需要小心。

  實際上,筆者在書寫示例代碼時,首先書寫的是如下程序(只保留核心部分,讀者可以比較一下與上面示例的微小不同),結果輸出的兩個時間總是相同的,而不是相隔8個小時。

1     time_t t = time( NULL );
2     t_in_tm = localtime( &t );          //將time_t類型的數值參數轉換為tm結構體中保存(本地時間)
3     local_time = asctime( t_in_tm );    //將tm類型結構體中的數值轉換為字符串形式
4
5     t_in_tm = gmtime( &t );             //將time_t類型的數值參數轉換為tm結構體中保存(UTC時間)
6     UTC_time = asctime( t_in_tm );      //將tm類型結構體中的數值轉換為字符串形式
7 
8     printf("local time is %s\nUTC time is %s\n",local_time,UTC_time);

  原因解釋:在第一次函數調用返回( 2,3行),函數返回的是指向靜態緩沖區中 tm 結構和字符串所在內存的地址。在第二次返回對應結構的內存地址指針時( 5,6行),由於公用靜態緩沖區,后續 gmtime 和 asctime 函數使用的內存空間與 localtime 和 asctime使用的內存空間相同。即第二次操作是在同樣的緩沖區中操作。結果就是,local_time和UTC_time指向的是同一片內存區域,且該區域最后一次是由第6行操作改變的,從而使的兩個字符串輸出的都是UTC時間形式。這也從側面反應出共用靜態緩沖區可能帶來的弊端。

 

  更高精度的時間獲取,可以參考博客 Windows獲取當前系統時間


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM